#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
PDD (拼多多) 商家后台爬虫工具
自动登录PDD商家后台并提取商品数据
"""

import time
import json
import logging
import os
import sys
from typing import Dict, List, Optional, Any
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import requests
from faker import Faker

# 添加项目根目录到路径（用于导入webdriver_manager_util）
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if project_root not in sys.path:
    sys.path.insert(0, project_root)

# 导入WebDriver管理器
try:
    from webdriver_manager_util import WebDriverManager
except ImportError:
    print("⚠️ 无法导入webdriver_manager_util，将使用传统方式")
    WebDriverManager = None

try:
    from .config import LOGIN_SELECTORS
except ImportError:
    from PDD.config import LOGIN_SELECTORS

# 配置日志系统
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('pdd_scraper.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

def get_random_ua():
    """获取随机User-Agent"""
    return Faker().user_agent()

class PDDScraper:
    def __init__(self, headless: bool = False):
        """
        初始化PDD爬虫
        
        参数:
            headless: 是否以无头模式运行浏览器
        """
        # 设置logger
        self.logger = logging.getLogger('PDDScraper')
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
            self.logger.setLevel(logging.INFO)
        
        # 保存headless设置
        self.headless = headless
        
        self.driver = None
        self.wait = None
        self.session = requests.Session()
        self.cookies = {}
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
            'Accept': 'application/json, text/plain, */*',
            'Accept-Encoding': 'gzip, deflate, br',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Content-Type': 'application/json',
            'Origin': 'https://mms.pinduoduo.com',
            'Referer': 'https://mms.pinduoduo.com/',
            'Sec-Fetch-Dest': 'empty',
            'Sec-Fetch-Mode': 'cors',
            'Sec-Fetch-Site': 'same-origin',
        }
        
        # GUI回调函数
        self.login_confirmation_callback = None
        self.verification_callback = None
        self.credential_input_callback = None
        
        self.setup_driver(headless)
    
    def set_login_confirmation_callback(self, callback):
        """设置登录确认回调函数"""
        self.login_confirmation_callback = callback
    
    def set_verification_callback(self, callback):
        """设置验证码处理回调函数"""
        self.verification_callback = callback
    
    def set_credential_input_callback(self, callback):
        """设置凭证输入回调函数"""
        self.credential_input_callback = callback

    def setup_driver(self, headless: bool):
        """设置Chrome WebDriver及相关选项"""
        try:
            # 调用新的初始化方法
            self._init_driver()
            
            self.wait = WebDriverWait(self.driver, 10)
            self.logger.info("Chrome WebDriver 初始化成功")
            
        except Exception as e:
            self.logger.error(f"WebDriver 初始化失败: {e}")
            raise

    def login(self, username: str, password: str) -> bool:
        """
        登录PDD商家后台
        
        参数:
            username: PDD商家用户名
            password: PDD商家密码
            
        返回:
            bool: 登录成功返回True，失败返回False
        """
        try:
            logger.info("开始登录流程...")
            
            # 导航到登录页面
            login_url = "https://mms.pinduoduo.com/login/?redirectUrl=https%3A%2F%2Fmms.pinduoduo.com%2F"
            self.driver.get(login_url)
            time.sleep(3)
            
            logger.info("登录页面加载完成")
            
            # 等待页面加载并检查不同的登录方式
            try:
                login_control = self.wait.until(
                    EC.element_to_be_clickable((By.XPATH, "//*[text()='账号登录']"))
                )

                # 尝试找到用户名/密码输入框
                username_input = self.wait.until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, 
                        "input[type='text'], input[placeholder*='用户名'], input[placeholder*='手机'], input[placeholder*='账号']"))
                )
                
                password_input = self.driver.find_element(By.CSS_SELECTOR, 
                    "input[type='password'], input[placeholder*='密码']")
                
                # 清空并输入凭证 (先进行点击用户名密码登录)
                login_control.click()
                username_input.clear()
                username_input.send_keys(username)
                time.sleep(1)
                
                password_input.clear()
                password_input.send_keys(password)
                time.sleep(1)
                
                # 找到并点击登录按钮
                try:
                    # 优先查找包含"登录"文本的span的父级button
                    login_button = self.driver.find_element(By.XPATH, 
                        "//button[.//span[contains(text(), '登录')]]")
                except NoSuchElementException:
                    try:
                        # 查找直接包含"登录"文本的button
                        login_button = self.driver.find_element(By.XPATH, 
                            "//button[contains(text(), '登录')]")
                    except NoSuchElementException:
                        # 最后尝试通用选择器
                        login_button = self.driver.find_element(By.CSS_SELECTOR, 
                            "button[type='submit'], .login-btn, .btn-login")
                
                login_button.click()
                
                logger.info("已提交登录表单")
                
            except (TimeoutException, NoSuchElementException):
                logger.warning("未找到标准登录表单，检查其他登录方式")
                
                # 检查二维码登录或其他方式
                self.handle_alternative_login()
                
            # 等待登录完成
            time.sleep(5)
            
            # 检查登录是否成功
            if self.is_logged_in():
                logger.info("登录成功！")
                self.extract_cookies()
                return True
            else:
                logger.error("登录失败或需要额外验证")
                return False
                
        except Exception as e:
            logger.error(f"登录错误: {e}")
            return False
    
    def login_pdd(self, mode: str = "interactive") -> bool:
        """
        PDD登录 - 支持GUI回调
        
        Args:
            mode: 登录模式 ("interactive" 或 "manual")
            
        Returns:
            bool: 登录是否成功
        """
        try:
            logger.info(f"开始PDD登录流程 - 模式: {mode}")
            
            # 导航到登录页面
            login_url = "https://mms.pinduoduo.com/login/?redirectUrl=https%3A%2F%2Fmms.pinduoduo.com%2F"
            self.driver.get(login_url)
            time.sleep(3)
            
            if mode == "interactive":
                return self._interactive_pdd_login()
            elif mode == "manual":
                return self._manual_pdd_login()
            else:
                logger.error(f"不支持的登录模式: {mode}")
                return False
                
        except Exception as e:
            logger.error(f"PDD登录失败: {e}")
            return False
    
    def _interactive_pdd_login(self) -> bool:
        """交互式PDD登录 - 程序协助用户登录"""
        try:
            logger.info("开始交互式PDD登录")
            
            # 等待页面加载
            self.wait.until(EC.presence_of_element_located((By.XPATH, "//*[text()='账号登录']")))
            
            # 获取用户凭证
            if hasattr(self, 'credential_input_callback') and self.credential_input_callback:
                # 使用GUI回调获取凭证
                credentials = self.credential_input_callback("拼多多")
                if not credentials:
                    logger.error("用户取消登录")
                    return False
                username, password = credentials
            else:
                # 命令行交互式输入
                print("\n" + "="*60)
                print("🔐 PDD商家后台登录")
                print("="*60)
                username = input("请输入PDD用户名/手机号: ").strip()
                password = input("请输入PDD密码: ").strip()
            
            if not username or not password:
                logger.error("用户名或密码不能为空")
                return False
            
            # 点击账号登录选项卡
            login_control = self.driver.find_element(By.XPATH, "//*[text()='账号登录']")
            login_control.click()
            time.sleep(1)
            
            # 输入用户名
            username_input = self.wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, 
                    "input[type='text'], input[placeholder*='用户名'], input[placeholder*='手机'], input[placeholder*='账号']"))
            )
            username_input.clear()
            username_input.send_keys(username)
            time.sleep(1)
            
            # 输入密码
            password_input = self.driver.find_element(By.CSS_SELECTOR, 
                "input[type='password'], input[placeholder*='密码']")
            password_input.clear()
            password_input.send_keys(password)
            time.sleep(1)
            
            # 点击登录按钮
            try:
                login_button = self.driver.find_element(By.XPATH, 
                    "//button[.//span[contains(text(), '登录')]]")
            except NoSuchElementException:
                login_button = self.driver.find_element(By.XPATH, 
                    "//button[contains(text(), '登录')]")
            
            login_button.click()
            logger.info("已提交登录表单")
            
            # 等待登录完成并检查结果
            return self._wait_for_pdd_login_success()
            
        except Exception as e:
            logger.error(f"交互式PDD登录失败: {e}")
            return False
    
    def _manual_pdd_login(self) -> bool:
        """手动PDD登录 - 用户完全手动操作"""
        try:
            logger.info("开始手动PDD登录")
            
            print("\n" + "="*60)
            print("👤 PDD手动登录模式")
            print("="*60)
            print("请在浏览器中手动完成登录操作")
            print("-"*60)
            print("📋 操作步骤:")
            print("   1. 选择账号登录方式")
            print("   2. 输入用户名/手机号")
            print("   3. 输入密码")
            print("   4. 处理验证码（如果出现）")
            print("   5. 点击登录按钮")
            print("   6. 等待登录成功")
            print("-"*60)
            
            # 显示当前页面信息
            print(f"📍 当前页面: {self.driver.current_url}")
            print(f"📄 页面标题: {self.driver.title}")
            
            # 等待用户手动登录
            if hasattr(self, 'login_confirmation_callback') and self.login_confirmation_callback:
                # 使用GUI回调确认
                confirmed = self.login_confirmation_callback("拼多多")
            else:
                # 命令行模式
                input("\n✋ 请在浏览器中完成登录操作，然后按 Enter 键继续...")
                confirmed = True
            
            if confirmed:
                # 检查登录状态
                if self.is_logged_in():
                    logger.info("✅ PDD手动登录完成")
                    self.extract_cookies()
                    return True
                else:
                    logger.error("❌ PDD登录验证失败")
                    return False
            else:
                logger.info("❌ 用户取消PDD登录")
                return False
                
        except Exception as e:
            logger.error(f"手动PDD登录失败: {e}")
            return False
    
    def _wait_for_pdd_login_success(self) -> bool:
        """等待PDD登录成功"""
        try:
            # 等待登录完成
            time.sleep(5)
            
            # 检查登录是否成功
            if self.is_logged_in():
                logger.info("✅ PDD登录成功")
                self.extract_cookies()
                return True
            else:
                # 检查是否有验证码
                if self._check_verification_needed():
                    if hasattr(self, 'verification_callback') and self.verification_callback:
                        # 使用GUI回调处理验证码
                        action = self.verification_callback("拼多多", "登录验证")
                        if action == 'continue':
                            # 再次等待登录完成
                            time.sleep(5)
                            return self.is_logged_in()
                        elif action == 'skip':
                            return False
                        elif action == 'quit':
                            return False
                    else:
                        # 命令行模式处理验证码
                        print("⚠️ 检测到验证码，请手动处理...")
                        input("处理完成后按 Enter 继续...")
                        return self.is_logged_in()
                
                logger.error("❌ PDD登录失败")
                return False
                
        except Exception as e:
            logger.error(f"等待PDD登录完成时出错: {e}")
            return False
    
    def _check_verification_needed(self) -> bool:
        """检查是否需要验证码处理（保留向后兼容）"""
        return self._check_for_verification_issues()
    
    def _check_for_verification_issues(self) -> bool:
        """检查是否出现验证码或其他需要人工处理的问题"""
        try:
            # 检查常见的验证码元素
            verification_selectors = [
                # PDD常见验证码
                '.captcha', '.verification', '.verify',
                '[class*="captcha"]', '[class*="verify"]',
                'iframe[src*="captcha"]', 'iframe[src*="verify"]',
                # 滑块验证码
                '.slider_bg', '.slide-verify', '.slider-verify',
                '[class*="slider"]',
                # 点击验证码
                '.click-verify', '[class*="click-verify"]',
                # 图形验证码
                '.image-captcha', '[class*="image-captcha"]',
                # 登录相关
                '.login-form', '#loginname',
                # 通用验证元素
                '[id*="verify"]', '[id*="captcha"]'
            ]
            
            for selector in verification_selectors:
                try:
                    elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    if elements and any(elem.is_displayed() for elem in elements):
                        self.logger.warning(f"检测到验证元素: {selector}")
                        return True
                except:
                    continue
            
            # 检查页面标题是否包含验证相关关键词
            try:
                title = self.driver.title.lower()
                verification_keywords = ['验证', 'verify', 'captcha', '滑动', '点击', '登录', '安全']
                if any(keyword in title for keyword in verification_keywords):
                    self.logger.warning(f"页面标题包含验证关键词: {title}")
                    return True
            except:
                pass
            
            # 检查URL是否重定向到验证页面
            try:
                current_url = self.driver.current_url.lower()
                verification_url_keywords = [
                    'verify', 'captcha', 'login', 'security',
                    'risk', 'check', 'validate'
                ]
                
                if any(keyword in current_url for keyword in verification_url_keywords):
                    # 排除正常的商品列表和详情页
                    if 'goods_list' not in current_url and 'goods_detail' not in current_url:
                        self.logger.warning(f"URL重定向到验证页面: {current_url}")
                        return True
            except:
                pass
            
            # 检查页面内容是否包含验证相关文本
            try:
                page_text = self.driver.find_element(By.TAG_NAME, "body").text.lower()
                verification_text_keywords = [
                    '滑动验证', '点击验证', '图形验证码', '请完成验证',
                    '安全验证', '人机验证', '验证码', '异常访问',
                    '请稍候', '风险提示'
                ]
                
                if any(keyword in page_text for keyword in verification_text_keywords):
                    self.logger.warning(f"页面内容包含验证关键词")
                    return True
            except:
                pass
            
            return False
            
        except Exception as e:
            self.logger.error(f"验证检查失败: {e}")
            return False
    
    def _handle_verification_pause(self, context: str = "未知") -> bool:
        """处理验证码暂停，等待人工干预
        
        Args:
            context: 当前操作上下文（如"商品列表获取"、"商品详情获取"等）
        
        Returns:
            bool: True表示应该继续操作，False表示跳过当前操作
        """
        try:
            current_url = self.driver.current_url
            
            print("\n" + "="*80)
            print("🚨 PDD检测到验证码或页面异常！")
            print("="*80)
            print(f"📍 当前操作: {context}")
            print(f"🌐 当前URL: {current_url}")
            print(f"📄 页面标题: {self.driver.title}")
            print("-"*80)
            print("📋 请在浏览器中完成以下操作:")
            print("   1. 完成滑块验证（如果有）")
            print("   2. 完成点击验证码（如果有）")
            print("   3. 输入图形验证码（如果有）")
            print("   4. 完成登录验证（如果需要）")
            print("   5. 等待页面恢复正常")
            print("-"*80)
            print("💡 处理完成后选择:")
            print("   - 选择'c'继续：验证完成后继续当前操作")
            print("   - 选择's'跳过：跳过当前操作，继续下一个")
            print("   - 选择'q'退出：完全退出程序")
            print("="*80)
            
            # 使用GUI回调或命令行交互
            if hasattr(self, 'verification_callback') and self.verification_callback:
                # 使用GUI回调
                action = self.verification_callback("拼多多", context)
                if action == 'continue':
                    print("✅ 验证处理完成，继续当前操作...")
                    time.sleep(2)  # 给页面一点恢复时间
                    return True
                elif action == 'skip':
                    print("⏸️ 跳过当前操作")
                    return False
                elif action == 'quit':
                    print("🚪 退出程序")
                    exit(0)
                else:
                    print("❌ 用户取消操作，跳过当前操作")
                    return False
            else:
                # 命令行交互
                while True:
                    try:
                        choice = input("✋ 处理完成后输入: 'c'继续 / 's'跳过 / 'q'退出: ").strip().lower()
                        
                        if choice == 'c':
                            print("✅ 验证处理完成，继续当前操作...")
                            time.sleep(2)  # 给页面一点恢复时间
                            return True
                            
                        elif choice == 's':
                            print("⏭️  跳过当前操作")
                            return False
                            
                        elif choice == 'q':
                            print("🛑 用户选择退出程序")
                            raise KeyboardInterrupt("用户手动退出")
                            
                        else:
                            print("❌ 无效输入，请输入 'c'、's' 或 'q'")
                            continue
                            
                    except EOFError:
                        print("\n🛑 检测到输入中断，跳过当前操作")
                        return False
                    except KeyboardInterrupt:
                        print("\n🛑 用户中断程序")
                        raise
                    
        except Exception as e:
            self.logger.error(f"验证暂停处理失败: {e}")
            print("❌ 处理验证暂停时出错，跳过当前操作")
            return False

    def handle_alternative_login(self):
        """处理其他登录方式，如二维码登录"""
        try:
            # 检查二维码
            qr_elements = self.driver.find_elements(By.CSS_SELECTOR, 
                ".qr-code, .qrcode, [class*='qr'], [id*='qr']")
            
            if qr_elements:
                logger.info("检测到二维码登录，请手动扫码登录。")
                logger.info("等待手动登录完成...")
                
                # 等待最多60秒的手动登录
                for i in range(60):
                    if self.is_logged_in():
                        logger.info("手动登录完成！")
                        return True
                    time.sleep(1)
                    
                logger.warning("手动登录超时")
                return False
                
        except Exception as e:
            logger.error(f"处理其他登录方式时出错: {e}")
            return False

    def is_logged_in(self) -> bool:
        """检查是否成功登录"""
        try:
            # 检查成功登录的常见指标
            current_url = self.driver.current_url
            
            # 如果已离开登录页面，可能已登录
            if 'login' not in current_url.lower():
                return True
                
            # 检查用户信息或登出元素
            logout_indicators = self.driver.find_elements(By.CSS_SELECTOR, 
                ".user-info, .logout, .user-name, [class*='user'], [href*='logout']")
            
            if logout_indicators:
                return True
                
            # 检查主导航或仪表板元素
            nav_indicators = self.driver.find_elements(By.CSS_SELECTOR, 
                ".main-nav, .dashboard, .goods-list, [href*='goods']")
            
            return len(nav_indicators) > 0
            
        except Exception as e:
            logger.error(f"检查登录状态时出错: {e}")
            return False

    def extract_cookies(self):
        """从浏览器会话中提取cookies"""
        try:
            browser_cookies = self.driver.get_cookies()
            self.cookies = {cookie['name']: cookie['value'] for cookie in browser_cookies}
            
            # 使用重要的token更新会话头
            for cookie in browser_cookies:
                if cookie['name'] in ['JSESSIONID', 'PASS_ID', 'api_uid', '_bee', 'rckk']:
                    self.session.cookies.set(cookie['name'], cookie['value'])
            
            logger.info(f"提取了 {len(self.cookies)} 个cookies")
            
        except Exception as e:
            logger.error(f"提取cookies时出错: {e}")

    def navigate_to_goods_list(self) -> bool:
        """导航到商品列表页面"""
        try:
            logger.info("正在导航到商品列表...")
            
            # 首先尝试直接URL
            goods_url = "https://mms.pinduoduo.com/goods/goods_list"
            self.driver.get(goods_url)
            time.sleep(3)
            
            # 🔒 验证码检测：导航后检查页面状态
            if self._check_for_verification_issues():
                logger.warning("导航到商品列表后检测到验证码")
                if not self._handle_verification_pause("商品列表页导航"):
                    logger.info("用户选择跳过")
                    return False
                # 用户选择继续，给页面恢复时间
                time.sleep(2)
            
            # 等待商品列表加载
            self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 
                ".goods-list, .product-list, [class*='goods'], [class*='product']")))
            
            logger.info("成功导航到商品列表")
            return True
            
        except Exception as e:
            logger.error(f"导航到商品列表时出错: {e}")
            return False

    def get_product_data_from_page(self) -> List[Dict]:
        """
        从页面UI直接提取商品数据
        
        返回:
            商品数据列表
        """
        try:
            logger.info("开始从页面提取商品数据...")
            
            # 🔒 验证码检测：在开始提取商品前检查页面状态
            if self._check_for_verification_issues():
                logger.warning("检测到验证码，暂停处理")
                if not self._handle_verification_pause("商品列表获取"):
                    logger.info("用户选择跳过，返回空列表")
                    return []
                # 用户选择继续，重新检测
                time.sleep(2)
            
            # 等待表格加载完成
            table_selector = "table.TB_tableWrapper_5-161-0"
            WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, table_selector))
            )
            
            # 查找所有商品行
            product_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0")
            logger.info(f"找到 {len(product_rows)} 个商品行")
            
            products = []
            
            for i, row in enumerate(product_rows):
                try:
                    product_data = {}
                    
                    # 获取商品名称
                    try:
                        name_element = row.find_element(By.CSS_SELECTOR, ".goods-name")
                        product_data['商品名称'] = name_element.text.strip()
                    except:
                        product_data['商品名称'] = "未找到商品名称"
                    
                    # 获取商品ID
                    try:
                        # 尝试多种方式获取商品ID
                        id_element = None
                        selectors = [
                            ".goods-id span[class^='id']",
                            ".goods-id",
                            "[class*='id']",
                            "td:contains('ID:')",
                        ]
                        
                        for selector in selectors:
                            try:
                                id_element = row.find_element(By.CSS_SELECTOR, selector)
                                if id_element and id_element.text.strip():
                                    break
                            except:
                                continue
                        
                        if id_element:
                            id_text = id_element.text.strip()
                            # 提取数字部分
                            import re
                            id_match = re.search(r'(\d+)', id_text)
                            if id_match:
                                product_data['商品ID'] = id_match.group(1)
                            else:
                                product_data['商品ID'] = id_text
                        else:
                            product_data['商品ID'] = "未找到ID"
                    except:
                        product_data['商品ID'] = "未找到ID"
                    
                    # 获取价格
                    try:
                        price_element = row.find_element(By.CSS_SELECTOR, ".price-tips_priceTip__EBnrK")
                        product_data['价格'] = price_element.text.strip()
                    except:
                        product_data['价格'] = "未找到价格"
                    
                    # 获取商品封面图
                    try:
                        img_element = row.find_element(By.CSS_SELECTOR, "img.image")
                        product_data['商品封面图'] = img_element.get_attribute('src')
                    except:
                        product_data['商品封面图'] = "未找到图片"
                    
                    # 获取总库存 (在第4列)
                    try:
                        cells = row.find_elements(By.CSS_SELECTOR, "td.TB_td_5-161-0")
                        if len(cells) >= 4:
                            stock_cell = cells[3]  # 总库存在第4列（从0开始计算）
                            stock_text = stock_cell.text.strip().split('\n')[0]  # 取第一行数字
                            product_data['总库存'] = stock_text
                        else:
                            product_data['总库存'] = "未找到库存"
                    except:
                        product_data['总库存'] = "未找到库存"
                    
                    # 获取收藏数 (在第5列)
                    try:
                        cells = row.find_elements(By.CSS_SELECTOR, "td.TB_td_5-161-0")
                        if len(cells) >= 5:
                            fav_cell = cells[4]  # 收藏在第5列
                            fav_text = fav_cell.text.strip().split('\n')[0]
                            product_data['收藏数'] = fav_text
                        else:
                            product_data['收藏数'] = "未找到收藏数"
                    except:
                        product_data['收藏数'] = "未找到收藏数"
                    
                    # 获取累计销量 (在第6列)
                    try:
                        cells = row.find_elements(By.CSS_SELECTOR, "td.TB_td_5-161-0")
                        if len(cells) >= 6:
                            sales_cell = cells[5]  # 累计销量在第6列
                            sales_text = sales_cell.text.strip().split('\n')[0]
                            product_data['累计销量'] = sales_text
                        else:
                            product_data['累计销量'] = "未找到销量"
                    except:
                        product_data['累计销量'] = "未找到销量"
                    
                    # 获取30日销量 (在第7列)
                    try:
                        cells = row.find_elements(By.CSS_SELECTOR, "td.TB_td_5-161-0")
                        if len(cells) >= 7:
                            sales30_cell = cells[6]  # 30日销量在第7列
                            sales30_text = sales30_cell.text.strip().split('\n')[0]
                            product_data['30日销量'] = sales30_text
                        else:
                            product_data['30日销量'] = "未找到30日销量"
                    except:
                        product_data['30日销量'] = "未找到30日销量"
                    
                    # 获取创建时间 (在第9列)
                    try:
                        cells = row.find_elements(By.CSS_SELECTOR, "td.TB_td_5-161-0")
                        if len(cells) >= 9:
                            time_cell = cells[8]  # 创建时间在第9列
                            time_text = time_cell.text.strip()
                            product_data['创建时间'] = time_text
                        else:
                            product_data['创建时间'] = "未找到创建时间"
                    except:
                        product_data['创建时间'] = "未找到创建时间"
                    
                    products.append(product_data)
                    logger.info(f"成功提取第{i+1}个商品数据: {product_data['商品名称']}")
                    
                except Exception as e:
                    logger.error(f"提取第{i+1}个商品数据时出错: {e}")
                    continue
            
            logger.info(f"总共提取了 {len(products)} 个商品数据")
            return products
            
        except Exception as e:
            logger.error(f"从页面提取商品数据时出错: {e}")
            return []

    def get_product_detail_by_click(self, product_link_element) -> Dict:
        """
        通过点击商品名称链接获取详细信息
        
        参数:
            product_link_element: 商品名称链接元素
            
        返回:
            商品详细信息字典
        """
        detail_data = {}
        original_window = self.driver.current_window_handle
        
        try:
            logger.info("点击商品名称链接进入详情页...")
            
            # 滚动到元素可见位置
            self.driver.execute_script("arguments[0].scrollIntoView(true);", product_link_element)
            time.sleep(1)
            
            # 点击商品名称链接
            product_link_element.click()
            time.sleep(3)
            
            # 检查是否打开了新标签页
            all_windows = self.driver.window_handles
            if len(all_windows) > 1:
                # 切换到新标签页
                for window in all_windows:
                    if window != original_window:
                        self.driver.switch_to.window(window)
                        break
            
            # 等待详情页加载并检查URL
            current_url = self.driver.current_url
            logger.info(f"当前页面URL: {current_url}")
            
            if 'goods_detail' in current_url:
                logger.info("成功进入商品详情页面")
                
                # 等待详情页内容加载
                try:
                    WebDriverWait(self.driver, 15).until(
                        EC.presence_of_element_located((By.CSS_SELECTOR, ".basic-and-preview"))
                    )
                except:
                    # 如果没有找到预期的元素，尝试等待其他可能的元素
                    try:
                        WebDriverWait(self.driver, 10).until(
                            EC.presence_of_element_located((By.CSS_SELECTOR, ".goods-detail-v2"))
                        )
                    except:
                        logger.warning("商品详情页面加载可能不完整")
                
                # 提取详细信息
                detail_data = self.extract_product_detail_from_current_page()
                
            else:
                logger.warning(f"未能进入商品详情页面，当前URL: {current_url}")
            
        except Exception as e:
            logger.error(f"通过点击获取商品详细信息时出错: {e}")
        
        finally:
            # 关闭详情页标签页并切换回原窗口
            try:
                all_windows = self.driver.window_handles
                if len(all_windows) > 1:
                    self.driver.close()  # 关闭当前标签页
                self.driver.switch_to.window(original_window)
                time.sleep(1)
            except Exception as e:
                logger.warning(f"关闭详情页时出错: {e}")
        
        return detail_data

    def get_product_detail_by_navigation(self, product_id: str) -> Dict:
        """
        通过直接导航到商品详情页获取信息（优化版本）
        
        参数:
            product_id: 商品ID
            
        返回:
            商品详细信息字典
        """
        detail_data = {}
        original_window = self.driver.current_window_handle
        detail_window = None
        
        try:
            # 🔄 使用新标签页打开详情页（避免影响商品列表页）
            detail_url = f"https://mms.pinduoduo.com/goods/goods_detail?goods_id={product_id}&from=goods_list"
            logger.info(f"📂 在新标签页打开商品详情: {product_id}")
            
            # 在新标签页打开
            self.driver.execute_script(f"window.open('{detail_url}', '_blank');")
            time.sleep(2)
            
            # 切换到新标签页
            all_windows = self.driver.window_handles
            if len(all_windows) > 1:
                detail_window = all_windows[-1]
                self.driver.switch_to.window(detail_window)
                logger.info(f"✅ 已切换到商品详情页标签")
            else:
                logger.warning("⚠️ 新标签页未打开")
                return {}
            
            # 等待页面加载
            time.sleep(3)
            
            # 🔒 验证码检测：导航到详情页后检查
            if self._check_for_verification_issues():
                logger.warning(f"详情页导航后检测到验证码: {product_id}")
                if not self._handle_verification_pause(f"商品详情页({product_id})"):
                    logger.info("用户选择跳过该商品详情")
                    return {}
                # 用户选择继续，给页面恢复时间
                time.sleep(2)
            
            # 检查是否成功加载
            new_url = self.driver.current_url
            logger.info(f"📍 详情页URL: {new_url}")
            
            if 'goods_detail' in new_url:
                # 检查是否出现浏览器版本警告
                try:
                    warning_text = self.driver.find_element(By.XPATH, "//*[contains(text(), '检测到您的浏览器版本过低')]")
                    if warning_text:
                        logger.warning("遇到浏览器版本警告，跳过该商品")
                        return {}
                except:
                    pass  # 没有警告，继续
                
                # 等待页面加载
                try:
                    WebDriverWait(self.driver, 15).until(
                        EC.any_of(
                            EC.presence_of_element_located((By.CSS_SELECTOR, ".basic-and-preview")),
                            EC.presence_of_element_located((By.CSS_SELECTOR, ".goods-detail-v2"))
                        )
                    )
                    logger.info("✅ 商品详情页面加载成功")
                    
                    # 提取详细信息（包含规格、单件预估实收等）
                    detail_data = self.extract_product_detail_from_current_page()
                    
                    logger.info(f"✅ 商品 {product_id} 详情提取完成")
                    
                except TimeoutException:
                    logger.warning("⚠️ 商品详情页面加载超时")
                    
            else:
                logger.warning(f"⚠️ 未能正确导航到商品详情页面，当前URL: {new_url}")
                
        except Exception as e:
            logger.error(f"❌ 通过导航获取商品详细信息时出错: {e}")
        
        finally:
            # 🔄 清理：关闭所有详情相关的标签页，确保回到商品列表页
            try:
                all_windows = self.driver.window_handles
                logger.info(f"🔍 当前共有 {len(all_windows)} 个标签页")
                
                # 关闭所有非主窗口的标签页
                for window in all_windows:
                    if window != original_window:
                        try:
                            self.driver.switch_to.window(window)
                            current_tab_url = self.driver.current_url
                            logger.info(f"🗑️ 关闭标签页: {current_tab_url[:80]}...")
                            self.driver.close()
                        except Exception as e:
                            logger.warning(f"⚠️ 关闭标签页时出错: {e}")
                
                # 切换回商品列表页主窗口
                self.driver.switch_to.window(original_window)
                time.sleep(0.5)
                
                # 验证是否成功回到商品列表页
                final_url = self.driver.current_url
                if 'goods_list' in final_url:
                    logger.info(f"✅ 已成功回到商品列表页")
                else:
                    logger.warning(f"⚠️ 当前页面可能不是商品列表页: {final_url}")
                    # 尝试导航回商品列表页
                    try:
                        self.driver.get("https://mms.pinduoduo.com/goods/goods_list")
                        time.sleep(2)
                        logger.info("🔄 已重新导航到商品列表页")
                    except:
                        pass
                
            except Exception as e:
                logger.error(f"❌ 清理标签页时出错: {e}")
                # 确保至少切换回主窗口
                try:
                    self.driver.switch_to.window(original_window)
                except:
                    pass
        
        return detail_data

    def extract_product_detail_from_current_page(self) -> Dict:
        """
        从当前商品详情页面提取详细信息
        
        返回:
            商品详细信息字典
        """
        detail_data = {}
        
        try:
            logger.info("开始从商品详情页提取信息...")
            
            # 提取商品分类
            try:
                category_element = self.driver.find_element(By.XPATH, "//div[text()='商品分类']/following-sibling::div")
                detail_data['商品分类'] = category_element.text.strip().replace(' &gt; ', ' > ')
                logger.info(f"成功提取商品分类: {detail_data['商品分类']}")
            except:
                logger.warning("未能提取商品分类")
                detail_data['商品分类'] = "未找到分类"
            
            # 提取商品标题
            try:
                title_element = self.driver.find_element(By.XPATH, "//div[text()='商品标题']/following-sibling::div")
                detail_data['商品标题'] = title_element.text.strip()
                logger.info(f"成功提取商品标题: {detail_data['商品标题']}")
            except:
                logger.warning("未能提取商品标题")
                detail_data['商品标题'] = "未找到标题"
            
            # 提取商品属性
            detail_data['商品属性'] = {}
            try:
                property_blocks = self.driver.find_elements(By.CSS_SELECTOR, ".property-list")
                for block in property_blocks:
                    try:
                        label_elem = block.find_element(By.CSS_SELECTOR, ".item-label")
                        value_elem = block.find_element(By.CSS_SELECTOR, ".item-value")
                        if label_elem and value_elem:
                            detail_data['商品属性'][label_elem.text.strip()] = value_elem.text.strip()
                    except:
                        continue
                logger.info(f"成功提取商品属性: {len(detail_data['商品属性'])} 个")
            except:
                logger.warning("未能提取商品属性")
            
            # 提取商品描述
            try:
                desc_element = self.driver.find_element(By.XPATH, "//div[text()='商品描述']/following-sibling::div")
                detail_data['商品描述'] = desc_element.text.strip()
                logger.info(f"成功提取商品描述")
            except:
                logger.warning("未能提取商品描述")
                detail_data['商品描述'] = "未找到描述"
            
            # 只提取商品封面图（第一张轮播图）
            try:
                carousel_imgs = self.driver.find_elements(By.CSS_SELECTOR, ".item-list.images.carousel .card-img")
                if carousel_imgs:
                    detail_data['商品封面图'] = carousel_imgs[0].get_attribute('src')
                    logger.info("成功提取商品封面图")
                else:
                    detail_data['商品封面图'] = "无封面图"
            except:
                logger.warning("未能提取商品封面图")
                detail_data['商品封面图'] = "无封面图"
            
            # 提取规格信息
            detail_data['规格款式'] = []
            try:
                # 滚动到规格表格位置
                try:
                    spec_table = self.driver.find_element(By.CSS_SELECTOR, ".TB_tableWrapper_5-161-0")
                    self.driver.execute_script("arguments[0].scrollIntoView(true);", spec_table)
                    time.sleep(2)
                except:
                    pass
                
                # 先获取表头，确定列的位置
                header_mapping = {}
                try:
                    header_rows = self.driver.find_elements(By.CSS_SELECTOR, "thead tr th")
                    for i, header in enumerate(header_rows):
                        header_text = header.text.strip()
                        logger.debug(f"表头列{i}: {header_text}")
                        
                        # 建立表头映射 - 兼容不同的表头名称
                        if any(keyword in header_text for keyword in ['颜色', '规格', '款式', '名称']) and '规格名称' not in header_mapping:
                            header_mapping['规格名称'] = i
                        elif '型号' in header_text:
                            header_mapping['型号'] = i
                        elif '库存' in header_text:
                            header_mapping['库存'] = i
                        elif '活动价' in header_text:  # 🆕 新增活动价识别
                            header_mapping['活动价'] = i
                        elif '拼单价' in header_text:
                            header_mapping['拼单价'] = i
                        elif '单买价' in header_text:
                            header_mapping['单买价'] = i
                        elif '规格编码' in header_text or '编码' in header_text:
                            header_mapping['规格编码'] = i
                        elif '预览图' in header_text or '图片' in header_text:
                            header_mapping['预览图'] = i
                        elif '状态' in header_text:
                            header_mapping['状态'] = i
                    
                    logger.debug(f"表头映射: {header_mapping}")
                    logger.info(f"✅ 成功识别表头，共{len(header_mapping)}个字段: {list(header_mapping.keys())}")
                    
                except Exception as e:
                    logger.warning(f"无法获取表头信息: {e}")
                    # 使用默认映射（适用于标准8列表格，包含活动价）
                    header_mapping = {
                        '规格名称': 0,
                        '库存': 1,
                        '活动价': 2,  # 🆕 新增
                        '拼单价': 3,
                        '单买价': 4,
                        '规格编码': 5,
                        '预览图': 6,
                        '状态': 7
                    }
                    logger.info(f"⚠️ 使用默认表头映射（含活动价）")
                
                # 提取规格数据行
                spec_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody[data-testid='beast-core-table-middle-tbody'] tr")
                for i, row in enumerate(spec_rows, 1):
                    try:
                        cells = row.find_elements(By.CSS_SELECTOR, "td")
                        
                        # 记录原始列数用于调试
                        logger.debug(f"规格行{i}: 共{len(cells)}列")
                        for j, cell in enumerate(cells[:min(len(cells), 8)]):  # 只记录前8列
                            logger.debug(f"  列{j}: {cell.text.strip()[:30]}")
                        
                        if len(cells) >= 3:  # 至少需要3列数据
                            # 根据表头映射提取数据
                            spec_name = ""
                            stock = ""
                            activity_price = ""  # 🆕 活动价
                            group_price = ""
                            single_price = ""
                            sku_code = ""
                            status = ""
                            
                            # 构建规格名称（可能需要合并多列）
                            if '规格名称' in header_mapping and header_mapping['规格名称'] < len(cells):
                                spec_name = cells[header_mapping['规格名称']].text.strip()
                                
                            # 如果有型号列，合并到规格名称中
                            if '型号' in header_mapping and header_mapping['型号'] < len(cells):
                                model = cells[header_mapping['型号']].text.strip()
                                if model and model != spec_name:
                                    if spec_name:
                                        spec_name = f"{spec_name} {model}"
                                    else:
                                        spec_name = model
                            
                            # 提取其他字段
                            if '库存' in header_mapping and header_mapping['库存'] < len(cells):
                                stock = cells[header_mapping['库存']].text.strip()
                            
                            # 🆕 提取活动价
                            if '活动价' in header_mapping and header_mapping['活动价'] < len(cells):
                                activity_price = cells[header_mapping['活动价']].text.strip()
                            
                            if '拼单价' in header_mapping and header_mapping['拼单价'] < len(cells):
                                group_price = cells[header_mapping['拼单价']].text.strip()
                            
                            if '单买价' in header_mapping and header_mapping['单买价'] < len(cells):
                                single_price = cells[header_mapping['单买价']].text.strip()
                            
                            if '规格编码' in header_mapping and header_mapping['规格编码'] < len(cells):
                                sku_code = cells[header_mapping['规格编码']].text.strip()
                            
                            if '状态' in header_mapping and header_mapping['状态'] < len(cells):
                                status = cells[header_mapping['状态']].text.strip()
                            
                            # 如果使用默认映射但表格列数不匹配，尝试智能识别
                            if not spec_name and len(cells) >= 1:
                                spec_name = cells[0].text.strip()
                            if not stock and len(cells) >= 2:
                                # 如果第二列是型号而不是库存，往后找库存
                                for col_idx in range(1, min(len(cells), 4)):
                                    col_text = cells[col_idx].text.strip()
                                    if col_text.isdigit() or '库存' in col_text:
                                        stock = col_text
                                        break
                            
                            # 构建规格信息
                            spec_info = {
                                '规格名称': spec_name,
                                '库存': stock,
                                '活动价': f"{activity_price}元" if activity_price and activity_price != "元" and activity_price != "--" else activity_price,  # 🆕 活动价
                                '拼单价': f"{group_price}元" if group_price and group_price != "元" and group_price != "--" else group_price,
                                '单买价': f"{single_price}元" if single_price and single_price != "元" and single_price != "--" else single_price,
                                '规格编码': sku_code if sku_code != "--" else "",
                                '状态': status
                            }
                            
                            # 验证关键字段不为空
                            if spec_info['规格名称']:
                                detail_data['规格款式'].append(spec_info)
                                logger.debug(f"成功提取规格{i}: {spec_info['规格名称']}")
                            else:
                                logger.warning(f"跳过空规格名称，行{i}")
                                
                    except Exception as e:
                        logger.error(f"提取规格行{i}时出错: {e}")
                        continue
                        
                if detail_data['规格款式']:
                    logger.info(f"成功提取 {len(detail_data['规格款式'])} 个规格")
                else:
                    logger.warning("未提取到任何规格信息")
                    
            except Exception as e:
                logger.warning(f"提取规格信息失败: {e}")
            
            # 提取其他信息（库存统计、发货信息等）
            self.extract_additional_product_info(detail_data)
            
            # 🆕 获取单件预估实收价格
            # 从URL中提取goods_id
            current_url = self.driver.current_url
            import re
            goods_id_match = re.search(r'goods_id=(\d+)', current_url)
            if goods_id_match:
                goods_id = goods_id_match.group(1)
                logger.info(f"📍 当前商品ID: {goods_id}")
                
                # 获取单件预估实收
                estimated_revenue = self.get_estimated_revenue_price(goods_id)
                if estimated_revenue:
                    detail_data['单件预估实收'] = estimated_revenue
                    logger.info(f"✅ 已添加单件预估实收: {estimated_revenue}")
                else:
                    detail_data['单件预估实收'] = "未找到"
                    logger.info("⚠️ 未获取到单件预估实收，使用默认值")
            else:
                logger.warning("⚠️ 无法从URL提取商品ID，跳过单件预估实收获取")
                detail_data['单件预估实收'] = "未找到"
            
            logger.info("商品详细信息提取完成")
            
        except Exception as e:
            logger.error(f"从详情页提取信息时出错: {e}")
        
        return detail_data

    def get_estimated_revenue_price(self, goods_id: str) -> str:
        """
        获取商品的单件预估实收价格
        从价格管理页面提取
        
        参数:
            goods_id: 商品ID
            
        返回:
            单件预估实收价格字符串，如"559.00元"，失败返回空字符串
        """
        original_window = self.driver.current_window_handle
        
        try:
            logger.info(f"🔍 获取商品 {goods_id} 的单件预估实收价格...")
            
            # 在新标签页打开价格管理页面
            price_mgmt_url = f"https://mms.pinduoduo.com/kit/goods-price-management?goods_id={goods_id}"
            self.driver.execute_script(f"window.open('{price_mgmt_url}', '_blank');")
            time.sleep(2)
            
            # 切换到新标签页
            all_windows = self.driver.window_handles
            if len(all_windows) > 1:
                self.driver.switch_to.window(all_windows[-1])
                logger.info(f"✅ 已切换到价格管理页面")
            else:
                logger.warning("⚠️ 新标签页未打开")
                return ""
            
            # 等待页面加载
            time.sleep(3)
            
            # 🔒 验证码检测：检查价格管理页面是否有验证码
            if self._check_for_verification_issues():
                logger.warning(f"价格管理页面检测到验证码")
                if not self._handle_verification_pause(f"价格管理页({goods_id})"):
                    logger.info("用户选择跳过，返回空值")
                    return ""
                # 用户选择继续，给页面恢复时间
                time.sleep(2)
            
            # 检查是否被重定向或页面加载失败
            current_url = self.driver.current_url
            if 'goods-price-management' not in current_url:
                logger.warning(f"⚠️ 页面跳转异常: {current_url}")
                # 可能被重定向，不继续提取
                return ""
            
            # 提取单件预估实收价格
            # 根据 jiageguanli HTML: <div class="goods-price-management_promoPrice__2wtAN"><span>559.00</span>
            estimated_revenue = ""
            try:
                # 等待价格元素加载
                WebDriverWait(self.driver, 10).until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, ".goods-price-management_promoPrice__2wtAN"))
                )
                
                # 提取单件预估实收价格
                price_element = self.driver.find_element(By.CSS_SELECTOR, ".goods-price-management_promoPrice__2wtAN span")
                estimated_revenue = price_element.text.strip()
                
                if estimated_revenue:
                    logger.info(f"✅ 成功获取单件预估实收: {estimated_revenue}元")
                else:
                    logger.warning("⚠️ 单件预估实收价格为空")
                    
            except TimeoutException:
                logger.warning(f"⚠️ 等待单件预估实收元素超时，可能该商品没有此数据")
            except NoSuchElementException:
                logger.warning(f"⚠️ 未找到单件预估实收元素，该商品可能没有此数据")
            except Exception as e:
                logger.warning(f"⚠️ 提取单件预估实收失败: {e}")
            
            return f"{estimated_revenue}元" if estimated_revenue and estimated_revenue != "--" else ""
            
        except Exception as e:
            logger.error(f"❌ 获取单件预估实收价格失败: {e}")
            return ""
        
        finally:
            # 关闭价格管理页面标签
            try:
                all_windows = self.driver.window_handles
                if len(all_windows) > 1:
                    self.driver.close()
                    logger.info("✅ 已关闭价格管理页面")
                
                # 切换回原窗口
                self.driver.switch_to.window(original_window)
                time.sleep(0.5)
            except Exception as e:
                logger.warning(f"⚠️ 关闭价格管理页面时出错: {e}")
                # 确保切换回主窗口
                try:
                    self.driver.switch_to.window(original_window)
                except:
                    pass
    
    def extract_additional_product_info(self, detail_data: Dict):
        """提取额外的商品信息（库存统计、发货信息等）"""
        try:
            # 提取库存统计信息
            detail_data['库存统计'] = {}
            try:
                # 滚动到信息区域
                try:
                    info_section = self.driver.find_element(By.CSS_SELECTOR, ".sku-info")
                    self.driver.execute_script("arguments[0].scrollIntoView(true);", info_section)
                    time.sleep(1)
                except:
                    pass
                
                stats_elements = [
                    ('总库存', "//div[text()='总库存']/following-sibling::div"),
                    ('拼单价', "//div[text()='拼单价']/following-sibling::div"),
                    ('单买价', "//div[text()='单买价']/following-sibling::div"),
                    ('商品参考价', "//div[text()='商品参考价']/following-sibling::div"),
                    ('满件折扣', "//div[text()='满件折扣']/following-sibling::div")
                ]
                
                for key, xpath in stats_elements:
                    try:
                        element = self.driver.find_element(By.XPATH, xpath)
                        detail_data['库存统计'][key] = element.text.strip()
                    except:
                        detail_data['库存统计'][key] = "未找到"
                        
            except Exception as e:
                logger.warning(f"提取库存统计信息失败: {e}")
            
            # 提取发货和配送信息
            detail_data['发货信息'] = {}
            detail_data['配送区域'] = {}
            detail_data['购买要求'] = {}
            detail_data['服务承诺'] = []
            
            try:
                # 滚动到服务信息区域
                try:
                    service_section = self.driver.find_element(By.XPATH, "//div[text()='服务与承诺']")
                    self.driver.execute_script("arguments[0].scrollIntoView(true);", service_section)
                    time.sleep(1)
                except:
                    pass
                
                # 发货信息
                shipping_elements = [
                    ('主要发货地', "//div[text()='主要发货地']/following-sibling::div"),
                    ('承诺发货时间', "//div[text()='承诺发货时间']/following-sibling::div"),
                    ('运费模板', "//div[text()='运费模板']/following-sibling::div//div[@class='template-name']")
                ]
                
                for key, xpath in shipping_elements:
                    try:
                        element = self.driver.find_element(By.XPATH, xpath)
                        detail_data['发货信息'][key] = element.text.strip()
                    except:
                        detail_data['发货信息'][key] = "未找到"
                
                # 配送区域信息
                try:
                    free_shipping_elem = self.driver.find_element(By.XPATH, "//span[text()='包邮配送区域']/../../div[@class='temp-list-text']")
                    detail_data['配送区域']['包邮区域'] = free_shipping_elem.text.strip()
                except:
                    detail_data['配送区域']['包邮区域'] = "未找到"
                
                # 付费配送区域
                detail_data['配送区域']['付费配送区域'] = []
                try:
                    paid_regions = self.driver.find_elements(By.CSS_SELECTOR, ".region-wrap")
                    for region in paid_regions:
                        try:
                            region_name = region.find_element(By.CSS_SELECTOR, ".template_costListContent__1dQ7w").text.strip()
                            cost_rule = region.find_element(By.CSS_SELECTOR, ".cost-text").text.strip()
                            detail_data['配送区域']['付费配送区域'].append({
                                '区域': region_name,
                                '付费规则': cost_rule
                            })
                        except:
                            continue
                except:
                    pass
                
                # 不配送区域
                try:
                    no_shipping_elem = self.driver.find_element(By.XPATH, "//span[text()='不配送区域']/../../div[@class='temp-list-text']")
                    detail_data['配送区域']['不配送区域'] = no_shipping_elem.text.strip()
                except:
                    detail_data['配送区域']['不配送区域'] = "未找到"
                
                # 购买要求
                requirement_elements = [
                    ('拼单要求', "//div[text()='拼单要求']/following-sibling::div"),
                    ('库存计件', "//div[text()='库存计件']/following-sibling::div")
                ]
                
                for key, xpath in requirement_elements:
                    try:
                        element = self.driver.find_element(By.XPATH, xpath)
                        detail_data['购买要求'][key] = element.text.strip()
                    except:
                        detail_data['购买要求'][key] = "未找到"
                
                # 服务承诺
                try:
                    promise_elems = self.driver.find_elements(By.CSS_SELECTOR, ".promise-list")
                    for promise_elem in promise_elems:
                        detail_data['服务承诺'].append(promise_elem.text.strip())
                    if not detail_data['服务承诺']:
                        detail_data['服务承诺'] = ["未找到服务承诺"]
                except:
                    detail_data['服务承诺'] = ["未找到服务承诺"]
                    
            except Exception as e:
                logger.warning(f"提取发货和服务信息失败: {e}")
                
        except Exception as e:
            logger.warning(f"提取额外商品信息失败: {e}")

    def get_product_detail_data(self, product_link_element) -> Dict:
        """
        获取单个商品的详细信息
        
        参数:
            product_link_element: 商品名称链接元素
            
        返回:
            商品详细信息字典
        """
        detail_data = {}
        original_window = self.driver.current_window_handle
        
        try:
            logger.info("点击商品名称进入详情页...")
            
            # 点击商品名称，会打开新标签页
            product_link_element.click()
            time.sleep(3)
            
            # 切换到新标签页
            all_windows = self.driver.window_handles
            for window in all_windows:
                if window != original_window:
                    self.driver.switch_to.window(window)
                    break
            
            # 等待详情页加载
            WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".basic-and-preview"))
            )
            
            logger.info("开始提取商品详细信息...")
            
            # 提取商品分类
            try:
                category_element = self.driver.find_element(By.XPATH, "//div[text()='商品分类']/following-sibling::div")
                detail_data['商品分类'] = category_element.text.strip()
            except:
                detail_data['商品分类'] = "未找到分类"
            
            # 提取商品标题
            try:
                title_element = self.driver.find_element(By.XPATH, "//div[text()='商品标题']/following-sibling::div")
                detail_data['商品标题'] = title_element.text.strip()
            except:
                detail_data['商品标题'] = "未找到标题"
            
            # 提取商品属性
            detail_data['商品属性'] = {}
            try:
                property_elements = self.driver.find_elements(By.CSS_SELECTOR, ".property-list")
                for prop in property_elements:
                    try:
                        label = prop.find_element(By.CSS_SELECTOR, ".item-label").text.strip()
                        value = prop.find_element(By.CSS_SELECTOR, ".item-value").text.strip()
                        detail_data['商品属性'][label] = value
                    except:
                        continue
            except:
                logger.warning("未能提取商品属性")
            
            # 提取商品描述
            try:
                desc_element = self.driver.find_element(By.XPATH, "//div[text()='商品描述']/following-sibling::div")
                detail_data['商品描述'] = desc_element.text.strip()
            except:
                detail_data['商品描述'] = "未找到描述"
            
            # 提取商品轮播图
            detail_data['商品轮播图'] = []
            try:
                carousel_images = self.driver.find_elements(By.CSS_SELECTOR, ".item-list.images.carousel .card-img")
                for img in carousel_images:
                    src = img.get_attribute('src')
                    if src:
                        detail_data['商品轮播图'].append(src)
            except:
                logger.warning("未能提取轮播图")
            
            # 提取商品详情图
            detail_data['商品详情图'] = []
            try:
                detail_images = self.driver.find_elements(By.CSS_SELECTOR, ".item-list.images .image-list.detail .card-img")
                for img in detail_images:
                    src = img.get_attribute('src')
                    if src:
                        detail_data['商品详情图'].append(src)
            except:
                logger.warning("未能提取详情图")
            
            logger.info("商品详细信息提取完成")
            
        except Exception as e:
            logger.error(f"提取商品详细信息时出错: {e}")
        
        finally:
            # 关闭详情页并切换回原窗口
            try:
                self.driver.close()
                self.driver.switch_to.window(original_window)
                time.sleep(1)
            except:
                pass
        
        return detail_data

    def get_product_detail_with_specs(self, product_id: str) -> Dict:
        """
        获取包含规格信息的完整商品详情
        
        参数:
            product_id: 商品ID
            
        返回:
            包含详细规格的商品信息
        """
        detail_data = {}
        
        try:
            # 构造商品详情URL
            detail_url = f"https://mms.pinduoduo.com/goods/goods_edit?goods_id={product_id}"
            self.driver.get(detail_url)
            time.sleep(5)
            
            logger.info(f"正在获取商品 {product_id} 的详细信息...")
            
            # 等待页面加载完成
            WebDriverWait(self.driver, 15).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".basic-and-preview"))
            )
            
            # 提取商品分类
            try:
                category_element = self.driver.find_element(By.XPATH, "//div[text()='商品分类']/following-sibling::div")
                detail_data['商品分类'] = category_element.text.strip().replace(' &gt; ', ' > ')
            except:
                detail_data['商品分类'] = "未找到分类"
            
            # 提取商品标题
            try:
                title_element = self.driver.find_element(By.XPATH, "//div[text()='商品标题']/following-sibling::div")
                detail_data['商品标题'] = title_element.text.strip()
            except:
                detail_data['商品标题'] = "未找到标题"
            
            # 提取商品属性
            detail_data['商品属性'] = {}
            try:
                property_blocks = self.driver.find_elements(By.CSS_SELECTOR, ".property-list")
                for block in property_blocks:
                    try:
                        label_elem = block.find_element(By.CSS_SELECTOR, ".item-label")
                        value_elem = block.find_element(By.CSS_SELECTOR, ".item-value")
                        if label_elem and value_elem:
                            detail_data['商品属性'][label_elem.text.strip()] = value_elem.text.strip()
                    except:
                        continue
            except:
                logger.warning("未能提取商品属性")
            
            # 提取商品描述
            try:
                desc_element = self.driver.find_element(By.XPATH, "//div[text()='商品描述']/following-sibling::div")
                detail_data['商品描述'] = desc_element.text.strip()
            except:
                detail_data['商品描述'] = "未找到描述"
            
            # 提取商品轮播图
            detail_data['商品轮播图'] = []
            try:
                carousel_imgs = self.driver.find_elements(By.CSS_SELECTOR, ".item-list.images.carousel .card-img")
                for img in carousel_imgs:
                    src = img.get_attribute('src')
                    if src and src not in detail_data['商品轮播图']:
                        detail_data['商品轮播图'].append(src)
            except:
                logger.warning("未能提取轮播图")
            
            # 提取商品详情图
            detail_data['商品详情图'] = []
            try:
                detail_imgs = self.driver.find_elements(By.CSS_SELECTOR, ".item-list.images .image-list.detail .card-img")
                for img in detail_imgs:
                    src = img.get_attribute('src')
                    if src and src not in detail_data['商品详情图']:
                        detail_data['商品详情图'].append(src)
            except:
                logger.warning("未能提取详情图")
            
            # 提取规格款式信息
            detail_data['规格款式'] = []
            try:
                # 等待规格表格加载
                WebDriverWait(self.driver, 10).until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, ".TB_tableWrapper_5-161-0"))
                )
                
                # 获取所有规格行
                spec_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody[data-testid='beast-core-table-middle-tbody'] tr")
                
                for i, row in enumerate(spec_rows, 1):
                    try:
                        spec_data = {}
                        cells = row.find_elements(By.CSS_SELECTOR, "td")
                        
                        if len(cells) >= 7:
                            # 规格名称 (第1列)
                            spec_name = cells[0].text.strip()
                            
                            # 库存 (第2列)
                            stock = cells[1].text.strip()
                            
                            # 拼单价 (第3列)
                            group_price = cells[2].text.strip()
                            
                            # 单买价 (第4列)
                            single_price = cells[3].text.strip()
                            
                            # 规格编码 (第5列)
                            spec_code = cells[4].text.strip()
                            
                            # 上下架状态 (第7列)
                            status = cells[6].text.strip()
                            
                            spec_info = {
                                '规格名称': spec_name,
                                '库存': stock,
                                '拼单价': f"{group_price}元",
                                '单买价': f"{single_price}元",
                                '规格编码': spec_code,
                                '状态': status
                            }
                            
                            detail_data['规格款式'].append(spec_info)
                            
                    except Exception as e:
                        logger.warning(f"提取第{i}个规格信息失败: {e}")
                        continue
                        
                logger.info(f"成功提取 {len(detail_data['规格款式'])} 个规格信息")
                
            except Exception as e:
                logger.warning(f"提取规格信息失败: {e}")
            
            # 提取库存统计信息
            detail_data['库存统计'] = {}
            try:
                # 总库存
                total_stock_elem = self.driver.find_element(By.XPATH, "//div[text()='总库存']/following-sibling::div")
                detail_data['库存统计']['总库存'] = total_stock_elem.text.strip()
                
                # 拼单价范围
                group_price_elem = self.driver.find_element(By.XPATH, "//div[text()='拼单价']/following-sibling::div")
                detail_data['库存统计']['拼单价'] = group_price_elem.text.strip()
                
                # 单买价范围
                single_price_elem = self.driver.find_element(By.XPATH, "//div[text()='单买价']/following-sibling::div")
                detail_data['库存统计']['单买价'] = single_price_elem.text.strip()
                
                # 商品参考价
                try:
                    ref_price_elem = self.driver.find_element(By.XPATH, "//div[text()='商品参考价']/following-sibling::div")
                    detail_data['库存统计']['商品参考价'] = ref_price_elem.text.strip()
                except:
                    detail_data['库存统计']['商品参考价'] = "未找到"
                
                # 满件折扣
                try:
                    discount_elem = self.driver.find_element(By.XPATH, "//div[text()='满件折扣']/following-sibling::div")
                    detail_data['库存统计']['满件折扣'] = discount_elem.text.strip()
                except:
                    detail_data['库存统计']['满件折扣'] = "无折扣"
                    
            except Exception as e:
                logger.warning(f"提取库存统计信息失败: {e}")
            
            # 提取发货信息
            detail_data['发货信息'] = {}
            try:
                # 承诺发货时间
                ship_time_elem = self.driver.find_element(By.XPATH, "//div[text()='承诺发货时间']/following-sibling::div")
                detail_data['发货信息']['承诺发货时间'] = ship_time_elem.text.strip()
                
                # 运费模板
                template_elem = self.driver.find_element(By.XPATH, "//div[text()='运费模板']/following-sibling::div//div[@class='template-name']")
                detail_data['发货信息']['运费模板'] = template_elem.text.strip()
                
            except Exception as e:
                logger.warning(f"提取发货信息失败: {e}")
            
            # 提取配送区域信息
            detail_data['配送区域'] = {}
            try:
                # 包邮配送区域
                try:
                    free_shipping_elem = self.driver.find_element(By.XPATH, "//span[text()='包邮配送区域']/../../div[@class='temp-list-text']")
                    detail_data['配送区域']['包邮区域'] = free_shipping_elem.text.strip()
                except:
                    detail_data['配送区域']['包邮区域'] = "未找到"
                
                # 付费配送区域
                detail_data['配送区域']['付费配送区域'] = []
                try:
                    paid_regions = self.driver.find_elements(By.CSS_SELECTOR, ".region-wrap")
                    for region in paid_regions:
                        try:
                            region_name = region.find_element(By.CSS_SELECTOR, ".template_costListContent__1dQ7w").text.strip()
                            cost_rule = region.find_element(By.CSS_SELECTOR, ".cost-text").text.strip()
                            detail_data['配送区域']['付费配送区域'].append({
                                '区域': region_name,
                                '收费规则': cost_rule
                            })
                        except:
                            continue
                except:
                    pass
                
                # 不配送区域
                try:
                    no_shipping_elem = self.driver.find_element(By.XPATH, "//span[text()='不配送区域']/../../div[@class='temp-list-text']")
                    detail_data['配送区域']['不配送区域'] = no_shipping_elem.text.strip()
                except:
                    detail_data['配送区域']['不配送区域'] = "未找到"
                    
            except Exception as e:
                logger.warning(f"提取配送区域信息失败: {e}")
            
            # 提取购买要求和服务承诺
            detail_data['购买要求'] = {}
            detail_data['服务承诺'] = []
            
            try:
                # 拼单要求
                try:
                    group_req_elem = self.driver.find_element(By.XPATH, "//div[text()='拼单要求']/following-sibling::div")
                    detail_data['购买要求']['拼单要求'] = group_req_elem.text.strip()
                except:
                    detail_data['购买要求']['拼单要求'] = "未找到"
                
                # 库存计件
                try:
                    stock_calc_elem = self.driver.find_element(By.XPATH, "//div[text()='库存计件']/following-sibling::div")
                    detail_data['购买要求']['库存计件'] = stock_calc_elem.text.strip()
                except:
                    detail_data['购买要求']['库存计件'] = "未找到"
                
                # 服务承诺
                try:
                    promise_elems = self.driver.find_elements(By.CSS_SELECTOR, ".promise-list")
                    for promise_elem in promise_elems:
                        detail_data['服务承诺'].append(promise_elem.text.strip())
                except:
                    detail_data['服务承诺'] = ["未找到服务承诺"]
                    
            except Exception as e:
                logger.warning(f"提取购买要求和服务承诺失败: {e}")
            
            logger.info(f"成功获取商品 {product_id} 的完整详细信息")
            
        except Exception as e:
            logger.error(f"获取商品详细信息时出错: {e}")
        
        return detail_data

    def get_all_products(self, max_pages: int = 10, get_details: bool = False) -> List[Dict]:
        """
        从页面UI获取所有商品数据（支持多页抓取）
        
        参数:
            max_pages: 最大获取页数，设为None或0表示获取所有页
            get_details: 是否获取详细信息
            
        返回:
            所有商品的列表
        """
        logger.info(f"开始从页面UI获取商品数据，最大页数: {max_pages}")
        
        all_products = []
        current_page = 1
        
        try:
            # 首先获取分页信息
            pagination_info = self.get_pagination_info()
            total_pages = pagination_info['total_pages']
            total_items = pagination_info['total_items']
            
            logger.info(f"🔍 分页信息 - 总商品数: {total_items}, 总页数: {total_pages}, 每页: {pagination_info['items_per_page']}条")
            
            # 确定实际要抓取的页数
            if max_pages is None or max_pages <= 0:
                target_pages = total_pages
                logger.info("🎯 将抓取所有页面")
            else:
                target_pages = min(max_pages, total_pages)
                logger.info(f"🎯 将抓取前 {target_pages} 页（共 {total_pages} 页）")
            
            # 逐页获取商品数据
            while current_page <= target_pages:
                logger.info(f"📄 正在处理第 {current_page}/{target_pages} 页...")
                
                # 获取当前页面的商品数据
                page_products = self.get_product_data_from_page()
                
                if page_products:
                    logger.info(f"✅ 第 {current_page} 页获取到 {len(page_products)} 个商品")
                    
                    # 为每个商品添加页码信息
                    for product in page_products:
                        product['页码'] = current_page
                        product['全局序号'] = len(all_products) + 1
                    
                    all_products.extend(page_products)
                else:
                    logger.warning(f"⚠️ 第 {current_page} 页未获取到商品数据")
                
                # 如果还有下一页且未达到目标页数，则翻页
                if current_page < target_pages:
                    if not self.go_to_next_page():
                        logger.warning(f"⚠️ 无法翻到第 {current_page + 1} 页，可能已到最后一页")
                        break
                    
                    # 🔒 验证码检测：翻页后检查是否出现验证码
                    if self._check_for_verification_issues():
                        logger.warning(f"翻页后检测到验证码")
                        if not self._handle_verification_pause(f"第{current_page + 1}页加载"):
                            logger.info("用户选择跳过翻页，停止获取")
                            break
                        # 用户选择继续，给页面恢复时间
                        time.sleep(2)
                
                current_page += 1
            
            logger.info(f"🎉 多页抓取完成！总共获取 {len(all_products)} 个商品（来自 {current_page-1} 页）")
            
            # 处理商品详细信息（如果需要）
            if all_products and get_details:
                logger.info("🔍 开始获取商品详细信息...")
                self._get_products_details(all_products)
                
        except Exception as e:
            logger.error(f"❌ 多页抓取过程中出错: {e}")
        
        return all_products

    def _get_products_details(self, products: List[Dict]):
        """
        批量获取商品详细信息（内部方法）
        
        参数:
            products: 商品列表，将直接修改此列表
        """
        logger.info(f"开始批量获取 {len(products)} 个商品的详细信息...")
        
        # 按页码分组处理商品详情
        pages_products = {}
        for product in products:
            page_num = product.get('页码', 1)
            if page_num not in pages_products:
                pages_products[page_num] = []
            pages_products[page_num].append(product)
        
        # 逐页处理商品详情
        for page_num in sorted(pages_products.keys()):
            page_products = pages_products[page_num]
            logger.info(f"📄 处理第 {page_num} 页的 {len(page_products)} 个商品详情...")
            
            # 导航到对应页面
            if page_num > 1:
                if not self.navigate_to_goods_list():
                    logger.error("无法导航到商品列表页面")
                    continue
                time.sleep(2)
                
                # 跳转到指定页码
                if not self.go_to_page(page_num):
                    logger.error(f"无法跳转到第 {page_num} 页")
                    continue
            
            # 处理当前页的商品详情
            for i, product in enumerate(page_products):
                try:
                    logger.info(f"🔍 获取第{product.get('全局序号', 'N/A')}个商品的详细信息: {product.get('商品名称', 'N/A')}")
                    
                    # 尝试通过导航获取详细信息
                    detail_data = None
                    product_id = product.get('商品ID', '').replace('ID: ', '').strip()
                    
                    if product_id and product_id != "未找到ID":
                        try:
                            detail_data = self.get_product_detail_by_navigation(product_id)
                            if detail_data:
                                logger.info(f"✅ 通过导航成功获取商品详细信息")
                            else:
                                logger.warning(f"⚠️ 导航方式获取详细信息失败")
                        except Exception as e:
                            logger.warning(f"导航方式失败: {e}")
                    
                    # 如果导航方式失败，尝试点击方式
                    if not detail_data:
                        try:
                            # 重新获取当前页面的商品行
                            product_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0")
                            if i < len(product_rows):
                                row = product_rows[i]
                                goods_name_element = row.find_element(By.CSS_SELECTOR, ".goods-name")
                                detail_data = self.get_product_detail_by_click(goods_name_element)
                                if detail_data:
                                    logger.info(f"✅ 通过点击成功获取商品详细信息")
                        except Exception as e:
                            logger.warning(f"点击方式也失败: {e}")
                    
                    # 更新商品信息
                    if detail_data:
                        product.update(detail_data)
                        logger.info(f"✅ 商品详细信息更新完成")
                    else:
                        logger.warning(f"⚠️ 商品详细信息获取失败，将只包含基础信息")
                        
                except Exception as e:
                    logger.error(f"❌ 获取商品详细信息失败: {e}")
                    continue
                        
        logger.info(f"🎉 批量获取商品详细信息完成！")

    def save_products_to_file(self, products: List[Dict], filename: str = "pdd_products.json"):
        """将商品保存到JSON文件"""
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(products, f, ensure_ascii=False, indent=2)
            logger.info(f"已将{len(products)}个商品保存到{filename}")
        except Exception as e:
            logger.error(f"保存商品时出错: {e}")

    def save_simplified_products(self, products: List[Dict], filename: str = "pdd_products_simplified.json"):
        """保存简化版本的商品数据，去除不必要的字段"""
        simplified_products = []
        
        for product in products:
            # 创建简化的商品数据
            simplified = {
                "商品名称": product.get('商品名称', ''),
                "商品ID": product.get('商品ID', ''),
                "价格": product.get('价格', ''),
                "商品封面图": product.get('商品封面图', ''),
                "总库存": product.get('总库存', ''),
                "收藏数": product.get('收藏数', ''),
                "累计销量": product.get('累计销量', ''),
                "30日销量": product.get('30日销量', ''),
                "创建时间": product.get('创建时间', '')
            }
            
            # 如果有详细信息，添加详细字段
            if product.get('商品分类'):
                simplified.update({
                    "商品分类": product.get('商品分类', ''),
                    "商品标题": product.get('商品标题', ''),
                    "商品属性": product.get('商品属性', {}),
                    "商品描述": product.get('商品描述', ''),
                    "规格款式": product.get('规格款式', []),
                    "库存统计": product.get('库存统计', {}),
                    "发货信息": product.get('发货信息', {}),
                    "配送区域": product.get('配送区域', {}),
                    "购买要求": product.get('购买要求', {}),
                    "服务承诺": product.get('服务承诺', [])
                })
            
            simplified_products.append(simplified)
        
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(simplified_products, f, ensure_ascii=False, indent=2)
            logger.info(f"已将{len(simplified_products)}个简化商品数据保存到{filename}")
        except Exception as e:
            logger.error(f"保存简化商品数据时出错: {e}")

    def format_detailed_product_info(self, product: Dict) -> str:
        """
        格式化单个商品的详细信息为简化模板格式
        
        参数:
            product: 包含详细信息的商品数据
            
        返回:
            格式化后的字符串
        """
        output = []
        
        # 商品分类
        if product.get('商品分类'):
            output.append("商品分类")
            output.append(f"{product['商品分类']}")
            output.append("")
        
        # 商品属性
        if product.get('商品属性') or product.get('商品描述'):
            output.append("商品属性")
            # 商品属性
            if product.get('商品属性'):
                for attr_name, attr_value in product['商品属性'].items():
                    output.append(f"{attr_name}: {attr_value}")
            # 商品描述
            if product.get('商品描述'):
                output.append(f"商品描述: {product['商品描述']}")
            output.append("")
        
        # 规格款式
        if product.get('规格款式'):
            output.append("规格款式：")
            for i, spec in enumerate(product['规格款式'], 1):
                spec_name = spec.get('规格名称', 'N/A')
                spec_detail = spec_name
                
                # 如果规格名称包含详细信息，添加到显示中
                if '-' in spec_name:
                    parts = spec_name.split('-')
                    if len(parts) >= 2:
                        spec_detail = f"{parts[0].strip()} - {parts[1].strip()}"
                
                output.append(f"{i}. {spec_detail}")
                output.append(f"   - 库存：{spec.get('库存', 'N/A')}")
                # 🆕 活动价
                if spec.get('活动价') and spec.get('活动价') != 'N/A' and spec.get('活动价') != '元':
                    output.append(f"   - 活动价：{spec.get('活动价')}")
                output.append(f"   - 拼单价：{spec.get('拼单价', 'N/A')}")
                output.append(f"   - 单买价：{spec.get('单买价', 'N/A')}")
                output.append(f"   - 规格编码：{spec.get('规格编码', 'N/A')}")
                output.append(f"   - 状态：{spec.get('状态', 'N/A')}")
                output.append("")
        
        # 库存统计
        if product.get('库存统计'):
            output.append("库存统计：")
            stats = product['库存统计']
            
            # 总库存
            if stats.get('总库存'):
                output.append(f"- 总库存：{stats['总库存']}")
            
            # 计算价格范围
            specs = product.get('规格款式', [])
            if specs:
                group_prices = []
                single_prices = []
                
                for spec in specs:
                    # 拼单价
                    group_price_str = spec.get('拼单价', '0元').replace('元', '')
                    try:
                        group_prices.append(float(group_price_str))
                    except:
                        pass
                    
                    # 单买价  
                    single_price_str = spec.get('单买价', '0元').replace('元', '')
                    try:
                        single_prices.append(float(single_price_str))
                    except:
                        pass
                
                if group_prices:
                    min_group = min(group_prices)
                    max_group = max(group_prices)
                    if min_group == max_group:
                        output.append(f"- 拼单价范围：{min_group:.2f}元")
                    else:
                        output.append(f"- 拼单价范围：{min_group:.2f}～{max_group:.2f}元")
                
                if single_prices:
                    min_single = min(single_prices)
                    max_single = max(single_prices)
                    if min_single == max_single:
                        output.append(f"- 单买价范围：{min_single:.2f}元")
                    else:
                        output.append(f"- 单买价范围：{min_single:.2f}～{max_single:.2f}元")
            
            # 商品参考价
            if stats.get('商品参考价'):
                output.append(f"- 商品参考价：{stats['商品参考价']}")
            
            output.append("")
        
        # 🆕 单件预估实收
        if product.get('单件预估实收') and product.get('单件预估实收') != '未找到':
            output.append("价格信息：")
            output.append(f"- 单件预估实收：{product['单件预估实收']}")
            output.append("")
        
        # 优惠活动
        if product.get('库存统计', {}).get('满件折扣') and product['库存统计']['满件折扣'] != '无折扣':
            output.append("优惠活动：")
            discount_info = product['库存统计']['满件折扣']
            output.append(f"- {discount_info}")
            output.append("")
        
        # 发货信息
        if product.get('发货信息'):
            output.append("发货信息：")
            shipping_info = product['发货信息']
            
            # 主要发货地
            if shipping_info.get('主要发货地'):
                output.append(f"- 主要发货地：{shipping_info['主要发货地']}")
            
            # 承诺发货时间
            if shipping_info.get('承诺发货时间'):
                output.append(f"- 承诺发货时间：{shipping_info['承诺发货时间']}")
            
            # 运费模板
            if shipping_info.get('运费模板'):
                output.append(f"- 运费模板：{shipping_info['运费模板']}")
            
            output.append("")
        
        # 配送区域
        if product.get('配送区域'):
            output.append("配送区域：")
            shipping = product['配送区域']
            
            # 包邮区域
            if shipping.get('包邮区域'):
                output.append(f"包邮区域：{shipping['包邮区域']}")
                output.append("")
            
            # 付费配送区域
            if shipping.get('付费配送区域') and shipping['付费配送区域']:
                paid_regions = shipping['付费配送区域']
                if paid_regions:
                    # 提取区域名称和规则
                    region_names = []
                    rules = []
                    
                    for region_info in paid_regions:
                        region_name = region_info.get('区域', '')
                        rule = region_info.get('付费规则', '')
                        if region_name:
                            region_names.append(region_name)
                        if rule:
                            rules.append(rule)
                    
                    if region_names:
                        output.append("付费配送区域：")
                        output.append(f"- {', '.join(region_names)}")
                        if rules:
                            output.append(f"- 付费规则：{rules[0]}")  # 通常规则是一样的
                        output.append("")
            
            # 不配送区域
            if shipping.get('不配送区域'):
                output.append(f"不配送区域：{shipping['不配送区域']}")
                output.append("")
        
        # 购买要求
        if product.get('购买要求'):
            output.append("购买要求：")
            requirements = product['购买要求']
            for key, value in requirements.items():
                output.append(f"- {key}：{value}")
            output.append("")
        
        # 服务承诺
        if product.get('服务承诺'):
            output.append("服务承诺：")
            for promise in product['服务承诺']:
                output.append(f"- {promise}")
            output.append("")
        
        return "\n".join(output)
    
    def export_detailed_format(self, products: List[Dict], filename: str = "detailed_products_formatted.txt"):
        """
        将商品详细信息导出为格式化的文本文件
        
        参数:
            products: 商品数据列表
            filename: 输出文件名
        """
        try:
            with open(filename, 'w', encoding='utf-8') as f:
                for i, product in enumerate(products, 1):
                    if product.get('规格款式'):  # 只导出有详细信息的商品
                        f.write(f"{'='*80}\n")
                        f.write(f"商品 {i}: {product.get('商品名称', 'N/A')}\n")
                        f.write(f"商品ID: {product.get('商品ID', 'N/A')}\n")
                        f.write(f"{'='*80}\n\n")
                        
                        formatted_info = self.format_detailed_product_info(product)
                        f.write(formatted_info)
                        f.write("\n\n")
            
            logger.info(f"格式化的详细信息已导出到 {filename}")
            
        except Exception as e:
            logger.error(f"导出格式化文件时出错: {e}")

    def print_products_summary(self, products: List[Dict]):
        """美化打印商品数据摘要"""
        if not products:
            print("没有商品数据可显示")
            return
        
        # 检查是否包含详细信息
        has_details = any('商品分类' in product for product in products)
        
        print(f"\n{'='*100}")
        title = "🛍️  PDD商品详细数据" if has_details else "🛍️  PDD商品基础数据"
        print(f"{title}  |  共找到 {len(products)} 个商品")
        print(f"{'='*100}")
        
        for i, product in enumerate(products, 1):
            print(f"\n📦 商品 {i}:")
            print(f"   📝 商品名称: {product.get('商品名称', 'N/A')}")
            print(f"   🆔 商品ID: {product.get('商品ID', 'N/A')}")
            print(f"   💰 价格: {product.get('价格', 'N/A')} 元")
            print(f"   📦 总库存: {product.get('总库存', 'N/A')}")
            print(f"   ❤️  收藏数: {product.get('收藏数', 'N/A')}")
            print(f"   📊 累计销量: {product.get('累计销量', 'N/A')}")
            print(f"   📈 30日销量: {product.get('30日销量', 'N/A')}")
            print(f"   📅 创建时间: {product.get('创建时间', 'N/A')}")
            print(f"   🖼️  商品封面图: {product.get('商品封面图', 'N/A')}")
            
            # 如果有详细信息，显示详细信息
            if has_details:
                print(f"\n   📋 详细信息:")
                if product.get('商品分类'):
                    print(f"      🏷️  商品分类: {product['商品分类']}")
                if product.get('商品标题'):
                    print(f"      📰 商品标题: {product['商品标题']}")
                if product.get('商品描述'):
                    print(f"      📄 商品描述: {product['商品描述']}")
                
                # 商品属性
                if product.get('商品属性'):
                    print(f"      🔧 商品属性:")
                    for attr_name, attr_value in product['商品属性'].items():
                        print(f"         • {attr_name}: {attr_value}")
                
                # 规格款式
                if product.get('规格款式'):
                    print(f"\n      📦 规格款式 ({len(product['规格款式'])} 个):")
                    for j, spec in enumerate(product['规格款式'][:5], 1):  # 只显示前5个
                        print(f"         {j}. {spec.get('规格名称', 'N/A')}")
                        print(f"            • 库存: {spec.get('库存', 'N/A')}")
                        print(f"            • 拼单价: {spec.get('拼单价', 'N/A')}")
                        print(f"            • 单买价: {spec.get('单买价', 'N/A')}")
                        print(f"            • 规格编码: {spec.get('规格编码', 'N/A')}")
                        print(f"            • 状态: {spec.get('状态', 'N/A')}")
                        if j < len(product['规格款式']) and j < 5:
                            print()
                    if len(product['规格款式']) > 5:
                        print(f"         ... 还有 {len(product['规格款式']) - 5} 个规格")
                
                # 库存统计
                if product.get('库存统计'):
                    print(f"\n      📊 库存统计:")
                    stats = product['库存统计']
                    for key, value in stats.items():
                        print(f"         • {key}: {value}")
                
                # 发货信息
                if product.get('发货信息'):
                    print(f"\n      🚚 发货信息:")
                    for key, value in product['发货信息'].items():
                        print(f"         • {key}: {value}")
                
                # 配送区域（简化显示）
                if product.get('配送区域'):
                    shipping = product['配送区域']
                    print(f"\n      🌍 配送区域:")
                    if shipping.get('包邮区域'):
                        regions = shipping['包邮区域']
                        if len(regions) > 100:  # 如果太长就截断显示
                            regions = regions[:100] + "..."
                        print(f"         • 包邮区域: {regions}")
                    if shipping.get('付费配送区域'):
                        print(f"         • 付费配送区域: {len(shipping['付费配送区域'])} 个")
                    if shipping.get('不配送区域'):
                        print(f"         • 不配送区域: {shipping['不配送区域']}")
                
                # 购买要求和服务承诺
                if product.get('购买要求'):
                    print(f"\n      📋 购买要求:")
                    for key, value in product['购买要求'].items():
                        print(f"         • {key}: {value}")
                
                if product.get('服务承诺'):
                    print(f"\n      🛡️  服务承诺:")
                    for promise in product['服务承诺']:
                        print(f"         • {promise}")
                
                # 轮播图和详情图数量
                carousel_count = len(product.get('商品轮播图', []))
                detail_count = len(product.get('商品详情图', []))
                if carousel_count > 0 or detail_count > 0:
                    print(f"\n      🖼️  图片资源:")
                    if carousel_count > 0:
                        print(f"         • 商品轮播图: {carousel_count} 张")
                    if detail_count > 0:
                        print(f"         • 商品详情图: {detail_count} 张")
            
            if i < len(products):
                print(f"   {'-'*80}")
        
        print(f"\n{'='*100}")
        status = "✅ 详细数据提取完成！" if has_details else "✅ 基础数据提取完成！"
        print(status)

    def close(self):
        """关闭浏览器并清理资源"""
        if self.driver:
            self.driver.quit()
            logger.info("浏览器已关闭")

    def convert_to_api_format(self, products: List[Dict]) -> List[Dict]:
        """
        将爬取的商品数据转换为后端API所需的格式
        
        参数:
            products: 爬取的商品数据列表
            
        返回:
            List[Dict]: 转换后的API格式数据列表
        """
        api_data_list = []
        
        for product in products:
            try:
                # 使用格式化文本作为product_data (类似pdd_products_formatted.txt的格式)
                product_data_text = self.format_detailed_product_info(product)
                
                # 生成商品URL（PDD商品详情页）
                product_id = product.get('商品ID', '')
                product_url = f"https://mms.pinduoduo.com/goods/goods_detail?goods_id={product_id}&from=goods_list" if product_id else None
                
                # 提取商品类型（从分类中提取第一层分类）
                product_category = product.get('商品分类', '')
                product_type = product_category.split(' > ')[0] if product_category and ' > ' in product_category else product_category
                product_type = str(product_type.split("/")[0])
                
                # 构建API格式数据
                api_data = {
                    "home_image": product.get('商品封面图', ''),
                    "product_name": product.get('商品名称', ''),
                    "product_type": product_type,
                    "product_data": product_data_text,
                    "product_url": product_url,
                    "platform_product_id": product.get('商品ID', '')
                }
                
                api_data_list.append(api_data)
                logger.info(f"成功转换商品数据: {product.get('商品名称', 'Unknown')}")
                
            except Exception as e:
                logger.error(f"转换商品数据时出错: {e}, 商品: {product.get('商品名称', 'Unknown')}")
                continue
                
        logger.info(f"总共转换了 {len(api_data_list)} 个商品数据")
        return api_data_list

    def submit_to_api(self, products: List[Dict[str, Any]], store_id: str) -> bool:
        """提交数据到API"""
        try:
            # 导入API配置
            import sys
            import os
            sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
            from api_config import APIConfig
            
            # 获取API配置
            api_url = APIConfig.get_products_api_url()
            
            if APIConfig.ENABLE_REQUEST_LOGGING:
                # 打印原始提取的商品数据
                print("\n" + "="*80)
                print("📦 PDD原始提取的商品数据:")
                print("="*80)
                for i, product in enumerate(products, 1):
                    print(f"\n🔍 原始商品 {i} 数据:")
                    for key, value in product.items():
                        if key == 'element':
                            continue  # 跳过WebElement对象
                        if isinstance(value, str) and len(value) > 100:
                            print(f"  {key}: {value[:100]}...")
                        else:
                            print(f"  {key}: {value}")
                print("="*80)
            
            # 直接使用传入的API格式数据（GUI监听器已经转换过了）
            api_products = products
            
            # 构建请求数据
            payload = {
                "store_id": store_id,
                "platform": APIConfig.PLATFORM_MAPPING.get("拼多多", "PDD"),
                "products": api_products
            }
            
            if APIConfig.ENABLE_REQUEST_LOGGING:
                # 打印详细的API数据到控制台
                print("\n" + "="*80)
                print("🚀 PDD准备提交到API的数据详情:")
                print("="*80)
                print(f"📋 Store ID: {store_id}")
                print(f"🏪 Platform: {APIConfig.PLATFORM_MAPPING.get('拼多多', 'PDD')}")
                print(f"📦 商品数量: {len(api_products)}")
                print(f"🌐 API地址: {api_url}")
                print("-"*80)
                
                for i, product in enumerate(api_products, 1):
                    print(f"\n📦 商品 {i}:")
                    print(f"  🏷️  商品名称: {product.get('product_name', 'N/A')}")
                    print(f"  🆔 商品ID: {product.get('platform_product_id', 'N/A')}")
                    # 从product_data字符串中提取价格
                    product_data_str = product.get('product_data', '')
                    price = 'N/A'
                    if isinstance(product_data_str, str) and '价格:' in product_data_str:
                        try:
                            # 从字符串中提取价格信息
                            import re
                            price_match = re.search(r'价格:\s*([^;]+)', product_data_str)
                            if price_match:
                                price = price_match.group(1).strip()
                        except:
                            pass
                    print(f"  💰 价格: {price}")
                    print(f"  🖼️  封面图: {product.get('home_image', 'N/A')[:80]}{'...' if len(str(product.get('home_image', ''))) > 80 else ''}")
                    print(f"  🔗 商品链接: {product.get('product_url', 'N/A')}")
                
                print("="*80)
                print("🔄 开始提交到API...")
                print("="*80)

            # 发送请求（支持重试）
            import requests
            import time
            
            for attempt in range(APIConfig.MAX_RETRIES):
                try:
                    if APIConfig.ENABLE_VERBOSE_LOGGING:
                        print(f"🔄 第 {attempt + 1}/{APIConfig.MAX_RETRIES} 次尝试提交...")
                    
                    response = requests.post(
                        api_url,
                        json=payload,
                        headers=APIConfig.DEFAULT_HEADERS,
                        timeout=APIConfig.REQUEST_TIMEOUT
                    )
                    
                    if APIConfig.ENABLE_RESPONSE_LOGGING:
                        print(f"📡 API响应状态码: {response.status_code}")
                        if response.text:
                            print(f"📄 API响应内容: {response.text[:500]}...")
                    
                    if response.status_code == 200:
                        print(f"✅ PDD API提交成功: {len(api_products)} 个商品")
                        logger.info(f"PDD API提交成功: store_id={store_id}, 商品数={len(api_products)}")
                        return True
                    else:
                        error_msg = f"API返回错误状态码: {response.status_code}"
                        if response.text:
                            error_msg += f" - {response.text}"
                        
                        if attempt < APIConfig.MAX_RETRIES - 1:
                            print(f"⚠️ {error_msg}，{APIConfig.RETRY_DELAY}秒后重试...")
                            time.sleep(APIConfig.RETRY_DELAY)
                        else:
                            print(f"❌ PDD API提交失败: {error_msg}")
                            logger.error(f"PDD API提交失败: {error_msg}")
                            return False
                            
                except requests.RequestException as e:
                    error_msg = f"网络请求异常: {e}"
                    if attempt < APIConfig.MAX_RETRIES - 1:
                        print(f"⚠️ {error_msg}，{APIConfig.RETRY_DELAY}秒后重试...")
                        time.sleep(APIConfig.RETRY_DELAY)
                    else:
                        print(f"❌ PDD API提交失败: {error_msg}")
                        logger.error(f"PDD API提交失败: {error_msg}")
                        return False
            
            return False
                
        except Exception as e:
            logger.error(f"PDD API提交异常: {e}")
            print(f"❌ PDD API提交异常: {e}")
            return False

    def send_to_api(self, api_data_list: List[Dict], api_endpoint: str, headers: Dict = None) -> bool:
        """
        将转换后的数据发送到后端API
        
        参数:
            api_data_list: 转换后的API格式数据列表
            api_endpoint: API接口地址
            headers: 请求头（可选）
            
        返回:
            bool: 发送成功返回True，失败返回False
        """
        if not headers:
            headers = {
                'Content-Type': 'application/json',
                'User-Agent': 'PDD-Scraper/1.0'
            }
        
        success_count = 0
        failed_count = 0
        
        for i, api_data in enumerate(api_data_list, 1):
            try:
                response = self.session.post(
                    api_endpoint,   # API接口地址
                    data=json.dumps(api_data, ensure_ascii=False),
                    headers=headers,
                    timeout=30
                )
                
                if response.status_code == 200:
                    success_count += 1
                    logger.info(f"成功发送商品 {i}/{len(api_data_list)}: {api_data['product_name']}")
                else:
                    failed_count += 1
                    logger.error(f"发送商品失败 {i}/{len(api_data_list)}: {api_data['product_name']}, 状态码: {response.status_code}, 响应: {response.text}")
                
                # 避免请求过快
                time.sleep(0.5)
                
            except Exception as e:
                failed_count += 1
                logger.error(f"发送商品时出错 {i}/{len(api_data_list)}: {api_data.get('product_name', 'Unknown')}, 错误: {e}")
                continue
        
        logger.info(f"API发送完成 - 成功: {success_count}, 失败: {failed_count}")
        return failed_count == 0

    def process_and_send_to_api(self, products: List[Dict], api_endpoint: str, headers: Dict = None) -> bool:
        """
        一站式处理：转换数据格式并发送到API
        
        参数:
            products: 爬取的商品数据列表
            api_endpoint: API接口地址
            headers: 请求头（可选）
            
        返回:
            bool: 处理成功返回True，失败返回False
        """
        try:
            logger.info("开始转换商品数据为API格式...")
            api_data_list = self.convert_to_api_format(products)
            
            if not api_data_list:
                logger.warning("没有可发送的数据")
                return False
            
            logger.info(f"开始发送 {len(api_data_list)} 个商品到API...")
            success = self.send_to_api(api_data_list, api_endpoint, headers)
            
            if success:
                logger.info("所有商品数据已成功发送到API")
            else:
                logger.warning("部分商品数据发送失败，请检查日志")
                
            return success
            
        except Exception as e:
            logger.error(f"处理并发送数据到API时出错: {e}")
            return False

    def send_to_api_batch(self, api_data_list: List[Dict], api_endpoint: str, headers: Dict = None, batch_size: int = 10, store_id: str = None) -> bool:
        """
        批量发送数据到后端API（新增方法）
        
        参数:
            api_data_list: 转换后的API格式数据列表
            api_endpoint: API接口地址
            headers: 请求头（可选）
            batch_size: 每批发送的商品数量
            
        返回:
            bool: 发送成功返回True，失败返回False
        """
        if not headers:
            headers = {
                'Content-Type': 'application/json',
                'User-Agent': 'PDD-Scraper/1.0'
            }
        
        success_count = 0
        failed_count = 0
        total_products = len(api_data_list)
        
        # 分批处理
        for i in range(0, total_products, batch_size):
            batch = api_data_list[i:i + batch_size]
            batch_num = (i // batch_size) + 1
            total_batches = (total_products + batch_size - 1) // batch_size
            
            # 构建批量数据格式
            batch_data = {
                "products": batch
            }
            
            # 如果提供了store_id，添加到请求中
            if store_id:
                batch_data["store_id"] = store_id
            
            try:
                logger.info(f"发送第 {batch_num}/{total_batches} 批数据，包含 {len(batch)} 个商品")
                
                response = self.session.post(
                    api_endpoint,
                    data=json.dumps(batch_data, ensure_ascii=False),
                    headers=headers,
                    timeout=60  # 批量请求可能需要更长时间
                )
                
                if response.status_code == 200:
                    success_count += len(batch)
                    logger.info(f"第 {batch_num} 批发送成功，包含 {len(batch)} 个商品")
                else:
                    failed_count += len(batch)
                    logger.error(f"第 {batch_num} 批发送失败，状态码: {response.status_code}, 响应: {response.text}")
                
                # 批次间延迟
                if i + batch_size < total_products:
                    time.sleep(1)
                
            except Exception as e:
                failed_count += len(batch)
                logger.error(f"第 {batch_num} 批发送时出错: {e}")
                continue
        
        logger.info(f"批量API发送完成 - 成功: {success_count}, 失败: {failed_count}")
        return failed_count == 0

    def process_and_send_to_api_batch(self, products: List[Dict], api_endpoint: str, headers: Dict = None, batch_size: int = 10) -> bool:
        """
        一站式批量处理：转换数据格式并批量发送到API
        
        参数:
            products: 爬取的商品数据列表
            api_endpoint: API接口地址
            headers: 请求头（可选）
            batch_size: 每批发送的商品数量
            
        返回:
            bool: 处理成功返回True，失败返回False
        """
        try:
            logger.info("开始转换商品数据为API格式...")
            api_data_list = self.convert_to_api_format(products)
            
            if not api_data_list:
                logger.warning("没有可发送的数据")
                return False
            
            logger.info(f"开始批量发送 {len(api_data_list)} 个商品到API（每批 {batch_size} 个）...")
            success = self.send_to_api_batch(api_data_list, api_endpoint, headers, batch_size)
            
            if success:
                logger.info("所有商品数据已成功批量发送到API")
            else:
                logger.warning("部分商品数据批量发送失败，请检查日志")
                
            return success
            
        except Exception as e:
            logger.error(f"批量处理并发送数据到API时出错: {e}")
            return False

    def save_api_format_data(self, products: List[Dict], filename: str = "api_format_data.json"):
        """
        保存API格式的数据到文件（用于调试和备份）
        
        参数:
            products: 爬取的商品数据列表
            filename: 保存文件名
        """
        try:
            api_data_list = self.convert_to_api_format(products)
            
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(api_data_list, f, ensure_ascii=False, indent=2)
            
            logger.info(f"API格式数据已保存到 {filename}")
            
        except Exception as e:
            logger.error(f"保存API格式数据时出错: {e}")

    def save_api_batch_format_data(self, products: List[Dict], filename: str = "api_batch_format_data.json", batch_size: int = 10):
        """
        保存批量API格式的数据到文件（用于调试和备份）
        
        参数:
            products: 爬取的商品数据列表
            filename: 保存文件名
            batch_size: 每批商品数量
        """
        try:
            api_data_list = self.convert_to_api_format(products)
            
            # 构建批量格式
            batch_data = {
                "products": api_data_list,
                "batch_info": {
                    "total_products": len(api_data_list),
                    "suggested_batch_size": batch_size,
                    "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
                }
            }
            
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(batch_data, f, ensure_ascii=False, indent=2)
            
            logger.info(f"批量API格式数据已保存到 {filename}")
            
        except Exception as e:
            logger.error(f"保存批量API格式数据时出错: {e}")

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    def get_pagination_info(self) -> Dict:
        """
        获取分页信息
        
        返回:
            包含分页信息的字典: {
                'total_items': 总商品数,
                'items_per_page': 每页商品数,
                'current_page': 当前页码,
                'total_pages': 总页数,
                'has_next': 是否有下一页
            }
        """
        try:
            pagination_info = {
                'total_items': 0,
                'items_per_page': 10,
                'current_page': 1,
                'total_pages': 1,
                'has_next': False
            }
            
            # 首先等待页面完全加载
            time.sleep(2)
            
            # 查找分页容器 - 使用多种选择器提高成功率
            pagination_container = None
            selectors = [
                "ul[data-testid='beast-core-pagination']",
                "ul[data-status*='beast-core-pagination']",
                ".TB_bottomRight_5-161-0 ul",
                "ul.PGT_outerWrapper_5-161-0"
            ]
            
            for selector in selectors:
                try:
                    pagination_container = self.driver.find_element(By.CSS_SELECTOR, selector)
                    logger.info(f"使用选择器 '{selector}' 找到分页容器")
                    break
                except:
                    continue
            
            if not pagination_container:
                logger.error("无法找到分页容器")
                # 尝试查看页面是否有商品
                try:
                    product_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0")
                    if product_rows:
                        logger.info(f"虽然无分页容器，但找到 {len(product_rows)} 个商品行，可能只有一页")
                        pagination_info['total_items'] = len(product_rows)
                        pagination_info['items_per_page'] = len(product_rows)
                        pagination_info['total_pages'] = 1
                        return pagination_info
                except:
                    pass
                return pagination_info
            
            # 获取总商品数
            try:
                # 尝试多种选择器
                total_selectors = [
                    ".PGT_totalText_5-161-0",
                    ".TB_pgtTotalText_5-161-0",
                    "li:contains('共有')",
                    "li[class*='totalText']"
                ]
                
                total_text = ""
                for selector in total_selectors:
                    try:
                        if ':contains(' in selector:
                            # 使用XPath处理contains
                            total_text_element = pagination_container.find_element(By.XPATH, 
                                ".//li[contains(text(), '共有')]")
                        else:
                            total_text_element = pagination_container.find_element(By.CSS_SELECTOR, selector)
                        total_text = total_text_element.text
                        logger.info(f"使用选择器 '{selector}' 获取到总数文本: '{total_text}'")
                        break
                    except:
                        continue
                
                if total_text:
                    import re
                    total_match = re.search(r'共有\s*(\d+)\s*条', total_text)
                    if total_match:
                        pagination_info['total_items'] = int(total_match.group(1))
                        logger.info(f"解析到总商品数: {pagination_info['total_items']}")
                    else:
                        logger.warning(f"无法从文本 '{total_text}' 中解析总商品数")
                else:
                    logger.warning("未找到总商品数文本")
            except Exception as e:
                logger.warning(f"获取总商品数失败: {e}")
            
            # 获取每页商品数
            try:
                page_size_selectors = [
                    "input[data-testid='beast-core-select-htmlInput']",
                    "input[class*='IPT_input']",
                    ".ST_selectValueSingle_5-161-0 input"
                ]
                
                for selector in page_size_selectors:
                    try:
                        page_size_input = pagination_container.find_element(By.CSS_SELECTOR, selector)
                        page_size_value = page_size_input.get_attribute('value')
                        if page_size_value and page_size_value.isdigit():
                            pagination_info['items_per_page'] = int(page_size_value)
                            logger.info(f"获取到每页商品数: {pagination_info['items_per_page']}")
                            break
                    except:
                        continue
            except Exception as e:
                logger.warning(f"获取每页商品数失败: {e}")
            
            # 计算总页数
            if pagination_info['total_items'] > 0:
                pagination_info['total_pages'] = (pagination_info['total_items'] - 1) // pagination_info['items_per_page'] + 1
            
            # 获取当前页码
            try:
                current_page_selectors = [
                    ".PGT_pagerItemActive_5-161-0",
                    "li[class*='pagerItemActive']",
                    ".PGT_pagerItem_5-161-0.PGT_pagerItemActive_5-161-0"
                ]
                
                for selector in current_page_selectors:
                    try:
                        current_page_element = pagination_container.find_element(By.CSS_SELECTOR, selector)
                        current_page_text = current_page_element.text.strip()
                        if current_page_text.isdigit():
                            pagination_info['current_page'] = int(current_page_text)
                            logger.info(f"获取到当前页码: {pagination_info['current_page']}")
                            break
                    except:
                        continue
            except Exception as e:
                logger.warning(f"获取当前页码失败: {e}")
            
            # 检查是否有下一页（下一页按钮是否可用）
            try:
                next_button_selectors = [
                    "li[data-testid='beast-core-pagination-next']",
                    ".PGT_next_5-161-0",
                    "li[class*='next']"
                ]
                
                for selector in next_button_selectors:
                    try:
                        next_button = pagination_container.find_element(By.CSS_SELECTOR, selector)
                        button_classes = next_button.get_attribute('class') or ""
                        # 检查是否包含disabled类
                        is_disabled = any(disabled_class in button_classes for disabled_class in 
                                        ['PGT_disabled_5-161-0', 'disabled', 'Disabled'])
                        pagination_info['has_next'] = not is_disabled
                        logger.info(f"下一页按钮状态: {'禁用' if is_disabled else '可用'}")
                        break
                    except:
                        continue
            except Exception as e:
                logger.warning(f"检查下一页状态失败: {e}")
            
            # 验证分页信息的合理性
            if pagination_info['total_items'] == 0:
                # 如果没有获取到总数，尝试通过商品行数估算
                try:
                    product_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0")
                    if product_rows:
                        logger.info(f"通过商品行数估算: 当前页有 {len(product_rows)} 个商品")
                        # 如果没有下一页，说明这就是全部商品
                        if not pagination_info['has_next']:
                            pagination_info['total_items'] = len(product_rows)
                            pagination_info['total_pages'] = 1
                        else:
                            # 有下一页，估算总数
                            pagination_info['total_items'] = len(product_rows) * 2  # 保守估计
                            pagination_info['total_pages'] = 2
                except:
                    pass
            
            logger.info(f"最终分页信息: {pagination_info}")
            return pagination_info
            
        except Exception as e:
            logger.error(f"获取分页信息失败: {e}")
            # 返回默认值，但尝试获取当前页商品数
            default_info = {
                'total_items': 0,
                'items_per_page': 10,
                'current_page': 1,
                'total_pages': 1,
                'has_next': False
            }
            
            try:
                product_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0")
                if product_rows:
                    default_info['total_items'] = len(product_rows)
                    logger.info(f"异常情况下通过商品行数获取: {len(product_rows)} 个商品")
            except:
                pass
            
            return default_info

    def go_to_next_page(self) -> bool:
        """
        翻到下一页
        
        返回:
            是否成功翻页
        """
        try:
            logger.info("准备翻到下一页...")
            
            # 获取翻页前的页码用于验证
            current_pagination = self.get_pagination_info()
            before_page = current_pagination.get('current_page', 1)
            logger.info(f"翻页前当前页码: {before_page}")
            
            # 查找下一页按钮 - 使用多种选择器
            next_button = None
            next_selectors = [
                "li[data-testid='beast-core-pagination-next']",
                ".PGT_next_5-161-0",
                "li[class*='next']:not([class*='disabled'])"
            ]
            
            for selector in next_selectors:
                try:
                    next_button = self.driver.find_element(By.CSS_SELECTOR, selector)
                    logger.info(f"使用选择器 '{selector}' 找到下一页按钮")
                    break
                except:
                    continue
            
            if not next_button:
                logger.error("无法找到下一页按钮")
                return False
            
            # 检查按钮是否被禁用
            button_classes = next_button.get_attribute('class') or ""
            disabled_classes = ['PGT_disabled_5-161-0', 'disabled', 'Disabled']
            is_disabled = any(disabled_class in button_classes for disabled_class in disabled_classes)
            
            if is_disabled:
                logger.info("下一页按钮已禁用，已到达最后一页")
                return False
            
            # 滚动到按钮位置确保可见
            try:
                self.driver.execute_script("arguments[0].scrollIntoView(true);", next_button)
                time.sleep(1)
            except:
                pass
            
            # 点击下一页按钮
            try:
                # 优先使用JavaScript点击，避免元素被遮挡
                self.driver.execute_script("arguments[0].click();", next_button)
                logger.info("使用JavaScript点击下一页按钮成功")
            except Exception as e:
                # 备用方案：直接点击
                try:
                    next_button.click()
                    logger.info("直接点击下一页按钮成功")
                except Exception as e2:
                    logger.error(f"点击下一页按钮失败: JS点击失败({e}), 直接点击也失败({e2})")
                    return False
            
            # 等待页面开始加载
            time.sleep(2)
            
            # 等待新页面内容加载完成 - 多种方式验证
            success = False
            
            # 方法1: 等待商品表格重新加载
            try:
                WebDriverWait(self.driver, 10).until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0"))
                )
                logger.info("商品表格加载完成")
                success = True
            except TimeoutException:
                logger.warning("等待商品表格加载超时")
            
            # 方法2: 验证页码是否改变
            if success:
                time.sleep(2)  # 再等待一下确保页码更新
                try:
                    after_pagination = self.get_pagination_info()
                    after_page = after_pagination.get('current_page', before_page)
                    
                    if after_page > before_page:
                        logger.info(f"翻页成功: {before_page} → {after_page}")
                        return True
                    else:
                        logger.warning(f"页码未变化: {before_page} → {after_page}，可能翻页失败")
                        # 但如果有商品内容，仍认为成功
                        try:
                            product_rows = self.driver.find_elements(By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0")
                            if product_rows:
                                logger.info(f"虽然页码未变，但找到 {len(product_rows)} 个商品，认为翻页成功")
                                return True
                        except:
                            pass
                        return False
                except Exception as e:
                    logger.warning(f"验证页码变化时出错: {e}")
                    return success  # 如果表格加载成功，就认为翻页成功
            
            return False
            
        except Exception as e:
            logger.error(f"翻页失败: {e}")
            return False

    def go_to_page(self, page_num: int) -> bool:
        """
        跳转到指定页码
        
        参数:
            page_num: 目标页码
            
        返回:
            是否成功跳转
        """
        try:
            # 查找指定页码的按钮
            page_button = self.driver.find_element(By.XPATH, 
                f"//li[contains(@class, 'PGT_pagerItem_5-161-0') and text()='{page_num}']")
            
            # 点击页码按钮
            self.driver.execute_script("arguments[0].click();", page_button)
            logger.info(f"点击页码 {page_num} 成功")
            
            # 等待页面加载
            time.sleep(3)
            
            # 等待新页面内容加载完成
            try:
                WebDriverWait(self.driver, 10).until(
                    EC.presence_of_element_located((By.CSS_SELECTOR, "tbody tr.TB_tr_5-161-0"))
                )
                logger.info(f"跳转到第 {page_num} 页成功")
                return True
            except TimeoutException:
                logger.error(f"等待第 {page_num} 页加载超时")
                return False
                
        except Exception as e:
            logger.warning(f"直接跳转到第 {page_num} 页失败: {e}")
            # 如果直接跳转失败，尝试逐页翻页
            current_page_info = self.get_pagination_info()
            current_page = current_page_info.get('current_page', 1)
            
            if page_num <= current_page:
                logger.warning(f"目标页码 {page_num} 小于等于当前页码 {current_page}")
                return False
                
            # 逐页翻页到目标页
            for _ in range(page_num - current_page):
                if not self.go_to_next_page():
                    logger.error(f"逐页翻页到第 {page_num} 页失败")
                    return False
                    
            logger.info(f"通过逐页翻页成功到达第 {page_num} 页")
            return True

    def _init_driver(self):
        """初始化浏览器驱动"""
        chrome_options = Options()
        if self.headless:
            chrome_options.add_argument('--headless')
        
        # 反检测配置
        chrome_options.add_argument('--disable-blink-features=AutomationControlled')
        chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
        chrome_options.add_experimental_option('useAutomationExtension', False)
        chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36')
        
        # 尝试使用WebDriverManager自动管理ChromeDriver
        if WebDriverManager:
            try:
                self.logger.info("🔍 使用WebDriverManager自动配置ChromeDriver...")
                manager = WebDriverManager(logger=self.logger)
                self.driver = manager.get_chrome_driver(options=chrome_options, headless=self.headless)
                self.logger.info("✅ ChromeDriver自动配置成功")
            except Exception as e:
                self.logger.warning(f"⚠️ WebDriverManager初始化失败: {e}")
                self.logger.info("🔄 回退到传统方式...")
                self._init_driver_legacy(chrome_options)
        else:
            # 如果没有WebDriverManager，使用传统方式
            self._init_driver_legacy(chrome_options)
        
        # 执行脚本避免被检测为自动化工具
        self.driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
        
        self.logger.info("🌐 浏览器驱动初始化成功")
    
    def _init_driver_legacy(self, chrome_options):
        """传统方式初始化driver（备用方案）"""
        try:
            # 使用本地chromedriver
            current_dir = os.path.dirname(os.path.abspath(__file__))
            chromedriver_path = os.path.join(current_dir, 'chromedriver.exe')
            
            if os.path.exists(chromedriver_path):
                self.logger.info(f"📂 使用本地ChromeDriver: {chromedriver_path}")
                service = Service(chromedriver_path)
                self.driver = webdriver.Chrome(service=service, options=chrome_options)
            else:
                self.logger.info("🔄 使用系统PATH中的ChromeDriver")
                self.driver = webdriver.Chrome(options=chrome_options)
                
        except Exception as e:
            self.logger.error(f"❌ 传统方式初始化ChromeDriver失败: {e}")
            raise


def main():
    """运行爬虫的主函数"""
    # 配置参数
    USERNAME = input("请输入PDD商户用户名: ").strip()
    PASSWORD = input("请输入PDD商户密码: ").strip()
    
    # 询问是否获取详细信息
    get_details = input("是否获取商品详细信息？(y/n，默认n): ").strip().lower() in ['y', 'yes', '是']
    
    # 询问是否发送到API
    send_to_api_choice = input("是否将数据发送到后端API？(y/n，默认n): ").strip().lower() in ['y', 'yes', '是']
    
    api_endpoint = None
    api_headers = None
    send_mode = "single"  # 默认单条发送
    batch_size = 10       # 默认批量大小
    
    if send_to_api_choice:
        api_endpoint = input("请输入API接口地址 (如: http://localhost:8000/api/products/): ").strip()
        if not api_endpoint:
            print("❌ 未提供API地址，将跳过API发送")
            send_to_api_choice = False
        else:
            # 选择发送模式
            print("\n📡 选择API发送模式:")
            print("1. 单条发送 (每个商品一个请求)")
            print("2. 批量发送 (多个商品一个请求)")
            mode_choice = input("请选择发送模式 (1/2，默认1): ").strip()
            
            if mode_choice == "2":
                send_mode = "batch"
                batch_size_input = input("请输入每批商品数量 (默认10): ").strip()
                if batch_size_input.isdigit():
                    batch_size = int(batch_size_input)
                print(f"✓ 选择批量发送模式，每批 {batch_size} 个商品")
            else:
                print("✓ 选择单条发送模式")
            
            # 可选：设置认证头
            auth_token = input("请输入认证Token (可选，直接回车跳过): ").strip()
            api_headers = {'Content-Type': 'application/json'}
            if auth_token:
                api_headers['Authorization'] = f'Bearer {auth_token}'
    
    try:
        with PDDScraper(headless=False) as scraper:
            # 登录
            if scraper.login(USERNAME, PASSWORD):
                # 导航到商品列表
                if scraper.navigate_to_goods_list():
                    # 等待页面完全加载
                    time.sleep(3)
                    
                    # 从页面UI获取商品数据
                    if get_details:
                        print("📋 正在获取商品基础信息和详细信息...")
                        products = scraper.get_all_products(get_details=True)
                    else:
                        print("📋 正在获取商品基础信息...")
                        products = scraper.get_all_products(get_details=False)
                    
                    if products:
                        # 保存简化版数据到文件
                        simplified_filename = "pdd_products_simplified.json" if get_details else "pdd_products.json"
                        scraper.save_simplified_products(products, simplified_filename)
                        
                        # 美化打印商品数据
                        scraper.print_products_summary(products)
                        
                        print(f"\n💾 简化数据已保存到 {simplified_filename}")
                        
                        if get_details:
                            # 导出格式化的详细信息文件
                            formatted_filename = "pdd_products_formatted.txt"
                            scraper.export_detailed_format(products, formatted_filename)
                            print("✨ 包含详细信息的简化数据已保存！")
                            print(f"📄 格式化的详细信息已导出到 {formatted_filename}")
                            print("\n📋 输出文件说明:")
                            print(f"   • {simplified_filename} - 简化JSON格式数据（去除冗余图片）")
                            print(f"   • {formatted_filename} - 按模板格式化的可读文本")
                            print("   • 只保留商品封面图，大幅减少文件大小")
                        
                        # 如果选择发送到API
                        if send_to_api_choice and api_endpoint:
                            print(f"\n📡 开始发送数据到API: {api_endpoint}")
                            print(f"📋 发送模式: {'批量发送' if send_mode == 'batch' else '单条发送'}")
                            
                            # 根据模式选择发送方法
                            if send_mode == "batch":
                                # 批量发送
                                success = scraper.process_and_send_to_api_batch(
                                    products=products,
                                    api_endpoint=api_endpoint,
                                    headers=api_headers,
                                    batch_size=batch_size
                                )
                                
                                # 保存批量格式数据作为备份
                                api_backup_filename = "api_batch_backup_data.json"
                                scraper.save_api_batch_format_data(products, api_backup_filename, batch_size)
                                print(f"💾 批量API格式数据已备份到 {api_backup_filename}")
                            else:
                                # 单条发送（原有方式）
                                success = scraper.process_and_send_to_api(
                                    products=products,
                                    api_endpoint=api_endpoint,
                                    headers=api_headers
                                )
                                
                                # 保存API格式数据作为备份
                                api_backup_filename = "api_backup_data.json"
                                scraper.save_api_format_data(products, api_backup_filename)
                                print(f"💾 API格式数据已备份到 {api_backup_filename}")
                            
                            if success:
                                print("✅ 所有商品数据已成功发送到API")
                            else:
                                print("❌ 部分数据发送失败，请检查日志文件")
                                print("💡 提示：可以稍后使用 api_integration_example.py 重新发送数据")
                    else:
                        print("❌ 未能获取商品数据，请检查页面是否正确加载")
                else:
                    print("❌ 无法访问商品列表页面")
            else:
                print("❌ 登录失败")
                
    except KeyboardInterrupt:
        print("\n🛑 程序被用户中断")
    except Exception as e:
        logger.error(f"程序执行错误: {e}")
        print(f"❌ 执行过程中出现错误: {e}")


if __name__ == "__main__":
    main()